проект книги: "Модули ядра Linux"

Здесь будут размещаться ссылки и отзывы на интересные публикации по Linux

Модераторы: Olej, vikos

Правила форума
Запрещается помещать сообщения, не имеющие отношения к обсуждаемой статье. Все такие сообщения будут удаляться непосредствено после обнаружения.
bose
Писатель
Сообщения: 107
Зарегистрирован: 23 фев 2012, 14:41
Откуда: Киев
Контактная информация:

Re: проект книги: "Модули ядра Linux"

Непрочитанное сообщение bose » 06 мар 2012, 14:41

Olej писал(а):Вот в том 2-х томнике Jerry Cooperstein (а Jerry Cooperstein - участник команды Линуса Торвальдса по разработке ядра, в отличие от авторов книг LDD и ELDD)
... у меня нет в доступе электронной копии скопировать, но для такого случая даже вручную перебью:
Я уже начал просматривать эту книгу )))
По поводу комадны Торвальдса пока не прочитал... но сам автор пишет что он считает себя человеком сделавшим незначительный вклад в ядро. Хотя нужно отдать должное автору - физик-ядерщик, работал консультантом в нефтедобывающей отрасли (его - "уравнения есть уравнения - описывают ли они столкновение ядер, взрывы звёзд, или сейсмические волны в земных слоях"), видимо неплохой программист (излишняя скромность наверное мешает ему в этом открыто признаться)
Olej писал(а): Всё! Больше нигде ни слова на все 2 тома.
Так вот по теме - он очень скользко обошёл этот вопрос:
Since use of proc has always suffered from a lack of standards and conventions, one should always evaluate whether or not proc is best choice (p. 162)
и далее
For reading just a few bytes, the callback function usually ignores these arguments.
....
Here's simple example of a module using proc read callback: (p. 163)
И далее идёт пример (как он и сказал) "For reading just a few bytes"

Аватара пользователя
Olej
Писатель
Сообщения: 21338
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Re: проект книги: "Модули ядра Linux"

Непрочитанное сообщение Olej » 06 мар 2012, 14:58

bose писал(а):
Olej писал(а):Вот в том 2-х томнике Jerry Cooperstein (а Jerry Cooperstein - участник команды Линуса Торвальдса по разработке ядра, в отличие от авторов книг LDD и ELDD)
... у меня нет в доступе электронной копии скопировать, но для такого случая даже вручную перебью:
Я уже начал просматривать эту книгу )))
А где вы её взяли? Т.е., может вы знаете URL электронной копии?

bose
Писатель
Сообщения: 107
Зарегистрирован: 23 фев 2012, 14:41
Откуда: Киев
Контактная информация:

Re: проект книги: "Модули ядра Linux"

Непрочитанное сообщение bose » 06 мар 2012, 15:05

Olej писал(а):
bose писал(а):
Olej писал(а):Вот в том 2-х томнике Jerry Cooperstein (а Jerry Cooperstein - участник команды Линуса Торвальдса по разработке ядра, в отличие от авторов книг LDD и ELDD)
... у меня нет в доступе электронной копии скопировать, но для такого случая даже вручную перебью:
Я уже начал просматривать эту книгу )))
А где вы её взяли? Т.е., может вы знаете URL электронной копии?
К сожалению на рапидшаре нашёл только отсканеную и не распознаную (OCR) пдф версию 1-го тома этой серии. Так что ссылаться в виде копи-паст тоже не могу (пока)
https://rapidshare.com/files/457302812/ ... rivers.pdf

bose
Писатель
Сообщения: 107
Зарегистрирован: 23 фев 2012, 14:41
Откуда: Киев
Контактная информация:

Re: проект книги: "Модули ядра Linux"

Непрочитанное сообщение bose » 06 мар 2012, 15:41

Olej писал(а): Интереснее другое: что в read_proc_t - половина параметров в прототипе "не используется" ... передумали :-o :lol:
Опровергну:
data - используется. Если в proc_dir_entry установить аттрибут data, то это значение будет передаваться при каждом вызове функции последним аргументом. (Проверил)

Сейчас интересно! Как утверждает Jerry Cooperstein:
The start argument is a left-over legacy from earlier implementation and isn't used.
Но это не так!
start - указывает на область памяти в адрессном пространстве ядра. Если инициализировать этот участок памяти значением указателя (например) статической переменной - дела идут в разнос. Т. е. неверно утверждать что ядро не контролирует значение этого аргумента. Вопрос только, как оно его использует...
Ответ поискал в (нелюбимом вами Alessandro Rubini) ЛДД3 (благо есть возможность сделать копи-паст):
thestart value is somewhat more complicated; its purpose is to
help with the implementation of large (greater than one page) /proc files.
The start parameter has a somewhat unconventional use. Its purpose is to indicate where (withinpage) the data to be returned to the user
is found. When your proc_read method is called, *start will be NULL. If you leave it NULL, the kernel assumes that the data has been
put into page as if offset were 0; in other words, it assumes a simple-minded version ofproc_read, which places the entire contents of the
virtual file in page without paying attention to theoffset parameter. If, instead, you set *start to a non-NULL value, the kernel assumes that
the data pointed to by *start takes offset into account and is ready to be returned directly to the user. In general, simpleproc_read
methods that return tiny amounts of data just ignore start. More complex methods set *start to page and only place data beginning at the
requested offset there.
Я ещё не проверил, но думаю он прав... ибо это может ответить на некоторые вопросы.

Аватара пользователя
Olej
Писатель
Сообщения: 21338
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Re: проект книги: "Модули ядра Linux"

Непрочитанное сообщение Olej » 06 мар 2012, 15:53

bose писал(а): Ответ поискал в (нелюбимом вами Alessandro Rubini) ЛДД3 (благо есть возможность сделать копи-паст):
Ну ... не настолько нелюбимом :oops:
Я сказал только, что очень не люблю их примеры, в которых мусора специфического разбирать приходится больше, чем смыслов.
А так ... - читаю с удовольствием. ;-)

А вы цитируйте по:
http://dmilvdv.narod.ru/Translate/LDD3/ ... ivers.html
- отлично сделанный полный перевод 2010 года.
И это LDD3 - последнее издание.
... и с копи-пастом всё путём... ;-)
http://dmilvdv.narod.ru/Translate/LDD3/ ... ead_proc_t
Как уже отмечалось выше, реализация больших файлов в /proc немного затруднительна. С течением времени методы /proc стали пользоваться дурной славой из-за ошибочных реализаций, когда объём вывода сильно увеличивается. Для очистки кода /proc и облегчения жизни программистам ядра был добавлен интерфейс seq_file.

Аватара пользователя
Olej
Писатель
Сообщения: 21338
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Re: проект книги: "Модули ядра Linux"

Непрочитанное сообщение Olej » 06 мар 2012, 16:12

Olej писал(а): ... и с копи-пастом всё путём... ;-)
http://dmilvdv.narod.ru/Translate/LDD3/ ... rying.html
Когда процесс читает из вашего файла в /proc, ядро выделяет страницу памяти (то есть PAGE_SIZE байт), куда драйвер может записать данные для возврата в пространство пользователя. Этот буфер передаётся в вашу функцию, которая представляет собой метод, названный read_proc:

int (*read_proc)(char *page, char **start, off_t offset, int count, int *eof, void *data);

Указатель page является буфером, куда вы будете записывать ваши данные; start используется функцией, чтобы сказать, где на странице были записаны интересующие данные (подробнее об этом позже); offset и count имеют такое же значение, как и для метода read. Аргумент eof указывает на целое число, которое должно быть установлено драйвером, чтобы сигнализировать, что у него нет больше данных для возвращения, в то время как data является указателем на специфические данные драйвера, которые можно использовать для внутренней бухгалтерии.

Эта функция должна возвращать количество байт данных, фактически размещённых в буфере page, так же как делает метод read для других файлов. Другие выходные значения - это *eof и *start. eof - это простой флаг, а вот использование значения start является несколько более сложным; его целью является помощь в реализации больших (более одной страницы) /proc файлов.

Параметр start имеет несколько нетрадиционное использование. Его целью является указать, где (в пределах страницы) находятся данные, которые будут возвращены пользователю. Когда вызывается метод proc_read, *start будет NULL. Если вы оставите его NULL, ядро предполагает, что данные были помещены на страницу, как если бы offset был 0; другими словами, оно предполагает простую версию proc_read, которая размещает всё содержимое виртуального файла на страницу, не обращая внимания на параметр смещения. Вместо этого, если вы установите *start в значение не-NULL, ядро предполагает, что данные, на которые указывает *start, принимают во внимание offset и готовы быть возвращены непосредственно к пользователю. В общем, простые методы proc_read, которые возвращают крошечные объёмы данных, просто игнорируют start. Более сложные методы устанавливают *start к page и размещают данные только начиная с запрошенного здесь смещения.

Давно существует другой важный вопрос с файлами /proc, которые также призван решить start. Иногда между последовательными вызовами read изменяется ASCII представление структур данных ядра, так что читающий процесс может обнаружить противоречивые данные от одного вызова к другому. Если *start установлен как небольшое целое значение, вызывающий использует его для увеличения filp->f_pos независимо от объёма возвращаемых данных, тем самым делая f_pos внутренним номером записи вашей процедуры read_proc. Если, например, ваша функция read_proc возвращает информацию из большого массива структур и пять из этих структур были возвращены в первом вызове, *start мог бы быть установлен в 5. Следующий вызов предоставляет то же значение, как offset; драйвер теперь знает, что надо начинать возвращать данные с шестой структуры в массиве. Это признается как "взлом" его авторами и это можно увидеть в fs/proc/generic.c.
Ну они там и накрутили ... блин :-o

Как вам? :
Если *start установлен как небольшое целое значение
В сочетании с:
char **start,
Это уже просто М.Жванецкий получается:
А вы не пробовали слабительное со снотворным?
Удивительный получается эффект!
:evil:

bose
Писатель
Сообщения: 107
Зарегистрирован: 23 фев 2012, 14:41
Откуда: Киев
Контактная информация:

Re: проект книги: "Модули ядра Linux"

Непрочитанное сообщение bose » 06 мар 2012, 16:21

Olej писал(а): А вы цитируйте по:
http://dmilvdv.narod.ru/Translate/LDD3/ ... ivers.html
- отлично сделанный полный перевод 2010 года.
И это LDD3 - последнее издание.
... и с копи-пастом всё путём... ;-)
http://dmilvdv.narod.ru/Translate/LDD3/ ... ead_proc_t
Спасибо за ссылочку. Только хотел пожаловаться что у ЛДД3 нет хорошего пдф (мне в этом формате удобней), как тут же она нарисовалась, да ещё и в переводе!!!
http://dmilvdv.narod.ru/Translate/LDD3/ ... s_3_ru.pdf

bose
Писатель
Сообщения: 107
Зарегистрирован: 23 фев 2012, 14:41
Откуда: Киев
Контактная информация:

Re: проект книги: "Модули ядра Linux"

Непрочитанное сообщение bose » 06 мар 2012, 17:35

Bingo! Я ещё не переварил всю информацию до конца, но кажется там есть ответы на все наши вопросы (касательно протокола работы ядра с имплементацией read_proc_t).
Ответ находиться здесь - fs/proc/generic.c (line 75):
/*
* How to be a proc read function
* ------------------------------
* Prototype:
* int f(char *buffer, char **start, off_t offset,
* int count, int *peof, void *dat)
*
* Assume that the buffer is "count" bytes in size.
*
* If you know you have supplied all the data you
* have, set *peof.
*
* You have three ways to return data:
* 0) Leave *start = NULL. (This is the default.)
* Put the data of the requested offset at that
* offset within the buffer. Return the number (n)
* of bytes there are from the beginning of the
* buffer up to the last byte of data. If the
* number of supplied bytes (= n - offset) is
* greater than zero and you didn't signal eof
* and the reader is prepared to take more data
* you will be called again with the requested
* offset advanced by the number of bytes
* absorbed. This interface is useful for files
* no larger than the buffer.
* 1) Set *start = an unsigned long value less than
* the buffer address but greater than zero.
* Put the data of the requested offset at the
* beginning of the buffer. Return the number of
* bytes of data placed there. If this number is
* greater than zero and you didn't signal eof
* and the reader is prepared to take more data
* you will be called again with the requested
* offset advanced by *start. This interface is
* useful when you have a large file consisting
* of a series of blocks which you want to count
* and return as wholes.
* (Hack by Paul.Russell@rustcorp.com.au)
* 2) Set *start = an address within the buffer.
* Put the data of the requested offset at *start.
* Return the number of bytes of data placed there.
* If this number is greater than zero and you
* didn't signal eof and the reader is prepared to
* take more data you will be called again with the
* requested offset advanced by the number of bytes
* absorbed.
*/
Там же имеется (чуть выше) такой комментарий:
/*
* Gaah, please just use "seq_file" instead. The legacy /proc
* interfaces cut loff_t down to off_t for reads, and ignore
* the offset entirely for writes..
*/
И этот негодняй ещё надсмехается над нами :evil:
Вобщем, осталось собрать элементы в целое... Сейчас буду переваривать :ugeek:

bose
Писатель
Сообщения: 107
Зарегистрирован: 23 фев 2012, 14:41
Откуда: Киев
Контактная информация:

Re: проект книги: "Модули ядра Linux"

Непрочитанное сообщение bose » 06 мар 2012, 17:54

Кстати, мои предположения оправдались ("грубо говоря - если смещение в странице осталось неизменным на протяжении работы функции"):
If the number of supplied bytes (= n - offset) is greater than zero and you didn't signal and the reader is prepared to take more data you will be called again with the requested
offset advanced by the number of bytes absorbed.
Только непонятно как читать обратное утверждение:
Если кол-во накопленных байт равно нулю ИЛИ(И)? вы сигнализировали eof....(по закону Моргана или :-) )

Аватара пользователя
Olej
Писатель
Сообщения: 21338
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Re: проект книги: "Модули ядра Linux"

Непрочитанное сообщение Olej » 06 мар 2012, 18:19

Olej писал(а):Но почему в обоих случаях двухкратный вызов чтения? - для меня пока загадка...
Что-то вы меня с толку сбили :-o
Вернёмся назад...

Конечно же, утилита cat делает 2 чтения, она делает нечто подобное:

Код: Выделить всё

int df = open( "/proc/mod_node", O_RDWR );
do {
   int res = read( df, buf, sizeof( buf ) );
} while ( res > 0 );
И конечно здесь 2 чтения:
- 1-е возвращает длину реально вычитанных данных (считаем что их меньше запрошенных sizeof( buf ))
- 2-е возвращает 0 как признак EOF, вызов read() userspace не имеет другого механизма для возврата EOF.

Просто тот факт, что мы на 1-м чтении будем чего-то возвращать как признак EOF, для read() - до фени, и он запросит следующее чтение...
Вот протокол выполнения с добавленной отладкой на выполнении: обратите внимание на off ! :

Код: Выделить всё

[olej@notebook proc]$ cat /proc/mod_node
Hello from module!
[olej@notebook proc]$ dmesg | tail -n30 | grep -v ^audit
! /proc/mod_node installed
! read: 3072 [buffer=f1f3f000, off=0, *eof=0]
! return bytes: 19
! EOF
! read: 3072 [buffer=f1f3f000, off=19, *eof=0]
! return bytes: 19
! EOF
Просто анализируя полученное в запросе eof, и сравнивая его с тем смещением, которое уже успели передать раньше, не нужно передавать данные (по-новой: адрес buffer не поменялся!), а нужно сразу отправлять EOF.

Ответить

Вернуться в «Публикации, книги и обсуждения»

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и 1 гость