чтение-запись данных ядра через /proc

Вопросы программного кода и архитектуры Linux

Модератор: Olej

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

Re: чтение-запись данных ядра через /proc

Непрочитанное сообщение Olej » 13 мар 2012, 13:45

Olej писал(а): 2. туда можно гонять данные ... туда-сюда, хоть символьные, хоть бинарные...
А вот тут я маху дал, увлёкся :oops:

1. в коде примера номер с бинарными данными не пройдёт, но только потому, что там я в нескольких местах опирался на функции strlen(), strcpy() ... т.е. которые предполагают терминальный '\0';

2. но это совсем не обязательно, нужно к буферу драйвера "приписать" поле length - актуальная длина данных...

3. для тестирования это будет полезно - сейчас перепишу примеры ;-)

4. ... но это при условии, что реализаторы read_proc_t в ядре не намудрили там в коде поддержки read_proc_t относительно терминального нуля...

5. с точки зрения практической ценности переделка п.3 ценности не имеет, мне кажется: а). передача бинарных данных через управляющие интерфейсы /proc & /sys - вряд ли есть хорошая идея, б). это противоречит традициям UNIX, когда любая управляющая информация, конфигурационные файлы и т.д. - всё по возможности представляется в текстовых форматах... в). бинарные форматы хорошо бы в Windows вписывались: ульи, там, пчёлы... :lol:

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

Re: чтение-запись данных ядра через /proc

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

Olej писал(а): Ну и кто здесь что понял? :-?
Ну в принципе понятно, только если уже знаешь как оно щёлкает (подсмотрев в исходниках), а так (если с первого раза, да и с третьего ) ясности мало.

При работе с read_proc_t я сделал следующие неаблюдаения, которые не очевидны из текстового описания (в различных источниках):
  • При каждом вызове функции можно отдать 3072 байта данных (как я уже говорил иногда катит 4096, но в 1 способе из трёх имеющихся)
  • Данные, которые мы отдаём из функции виртуально бесконечные, но отдавать мы их можем частями по 3КБ. Отсюда - смещение (параметр off), это смещение в наших данных, которые мы передаём, а не в буфере с помощью которого мы обмениваемся (просто в случае когда объём данных <3КБ, значение смещения может совпадать )
  • Смещение off - не всегда смещение в данных, которые ты передаёшь. Это может быть например индекс в массиве структур, или просто счётчик (это второй способ реализации функции, когда *start устанавливается в значение меньшее чем адресс буфера обмена). Тогда логика вычисления смещения(индекса) становится такой:

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

    *ppos += start < page ? (unsigned long)start : n;
    
  • Даже если твои данные влазят в 3КБ, но ты (по каким то причинам) их отдаёшь частями, то вернуться назад и перезаписать ранее отданные данные не получиться (после каждого вызова функции, данные отдаються в юзерское пространство, не используя какой-либо промежуточный буфер размером в страницу)
Ну, пока всё из особеннностей. которые мне показались не очевидными из описания у разных авторов и которые я вспомнил

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

Re: чтение-запись данных ядра через /proc

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

Olej писал(а): 1. в коде примера номер с бинарными данными не пройдёт, но только потому, что там я в нескольких местах опирался на функции strlen(), strcpy() ... т.е. которые предполагают терминальный '\0';
В include/linux/string.h есть набор функция mem*. Их удобно использовать для бинарных данных.

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

Re: чтение-запись данных ядра через /proc

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

bose писал(а):
Olej писал(а): 1. в коде примера номер с бинарными данными не пройдёт, но только потому, что там я в нескольких местах опирался на функции strlen(), strcpy() ... т.е. которые предполагают терминальный '\0';
В include/linux/string.h есть набор функция mem*. Их удобно использовать для бинарных данных.
Я знаю. Но так же точно всё решается с strncpy() вместо strcpy().
Здесь главный вопрос в точке зрения: считать данные самоопределёнными по длине (строка в С, которая ограничена содержащимся в ней байтом), или длина хранится где-то отдельным полем совместно с данными (строка PASCAL ... да, собственно, и класс string C++/STL).

Ну и то, что передавать бинарные данные через /proc & /sys - это ... оксюморон :lol: :
http://ru.wikipedia.org/wiki/%CE%EA%F1% ... E%F0%EE%ED
Оксю́морон, оксиморо́н (др.-греч. οξύμωρον — «умная глупость») — стилистическая фигура или стилистическая ошибка — сочетание слов с противоположным значением (то есть сочетание несочетаемого).
Последний раз редактировалось Olej 13 мар 2012, 14:56, всего редактировалось 1 раз.

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

Re: чтение-запись данных ядра через /proc

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

bose писал(а): При работе с read_proc_t я сделал следующие неаблюдаения, которые не очевидны из текстового описания (в различных источниках):
  • При каждом вызове функции можно отдать 3072 байта данных (как я уже говорил иногда катит 4096, но в 1 способе из трёх имеющихся)
Не пользуйтесь классификацией "в 1 способе из трёх имеющихся" - я уже давно не понимаю кто из них какой: 1-й, 2-1, 3-й, 4-й... Но я хоть внимательно слежу за темой, а если кто со стороны решит почитать? - да он с ума сойдёт! :twisted:

Или напишите явную квалификацию 1 раз: 1-й способ - это ... , 2-й способ - это ...
bose писал(а): [*]Данные, которые мы отдаём из функции виртуально бесконечные, но отдавать мы их можем частями по 3КБ. Отсюда - смещение (параметр off), это смещение в наших данных, которые мы передаём, а не в буфере с помощью которого мы обмениваемся (просто в случае когда объём данных <3КБ, значение смещения может совпадать )[/*]
[*]Смещение off - не всегда смещение в данных, которые ты передаёшь. Это может быть например индекс в массиве структур, или просто счётчик (это второй способ реализации функции, когда *start устанавливается в значение меньшее чем адресс буфера обмена). Тогда логика вычисления смещения(индекса) становится такой:
Мне это как-то непонятно и странно... off - это входной параметр, который нам передаётся как копия (по значению), который мы можем принять к сведению ... или не принять, но влиять на него никак не можем. Откуда тогда "не всегда"? "может быть"? ... если мы никак не можем влиять на то, что это может быть?
bose писал(а):

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

*ppos += start < page ? (unsigned long)start : n;
[/*]
Здесь меня тоже смущает вольница в толковании (типов).
start - это указатель на указатель ... это, как кому нравится, может быть: выходной (изменяемый) параметр вызова ... массив указателей, если кому так нравится :lol: - но
(unsigned long)start - это круто! в Linux повсеместно 32-бит толкуются то как целое, то как указатель (без каких либо преобразований) ... что потом создаёт им же проблемы при переходе к 64-бит, которые они успешно решают... :lol:
Но указатель на указатель - в целое? это круто ... господа понимают толк и вкус в настоящих извращениях :twisted:

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

Re: чтение-запись данных ядра через /proc

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

Olej писал(а):
bose писал(а):

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

*ppos += start < page ? (unsigned long)start : n;
[/*]
Здесь меня тоже смущает вольница в толковании (типов).
start - это указатель на указатель ... это, как кому нравится, может быть: выходной (изменяемый) параметр вызова ... массив указателей, если кому так нравится :lol: - но
(unsigned long)start - это круто! в Linux повсеместно 32-бит толкуются то как целое, то как указатель (без каких либо преобразований) ... что потом создаёт им же проблемы при переходе к 64-бит, которые они успешно решают... :lol:
Но указатель на указатель - в целое? это круто ... господа понимают толк и вкус в настоящих извращениях :twisted:
start - это указатель (не важно на что, хоть на слона).
Указатель и масив - разные типы и это не одно и то же (даже если это кому-то и нравится).
(http://en.wikipedia.org/wiki/C_data_types)

Ну и далее по делу:
According to the C standard, programs again cannot assume that pointers and unsigned long variables
can be typecast. However, because this is possible on all existing architectures, the kernel makes this
assumption a prerequisite and explicitly allows type conversion
Professional Linux Kernel Architecture - C.2.2 Pointer Type Conversions (p. 1201)
Although you must be careful when mixing different data types, sometimes there are
good reasons to do so. One such situation is for memory addresses, which are special
as far as the kernel is concerned. Although, conceptually, addresses are pointers,
memory administration is often better accomplished by using an unsigned integer
type; the kernel treats physical memory like a huge array, and a memory address is
just an indexinto the array. Furthermore, a pointer is easily dereferenced; when dealing
directly with memory addresses, you almost never want to dereference them in
this manner. Using an integer type prevents this dereferencing, thus avoiding bugs.
Therefore, generic memory addresses in the kernel are usually unsigned long, exploiting
the fact that pointers and long integers are always the same size, at least on all the
platforms currently supported by Linux
.
LDD3 - Chapter 11. Use of Standard C Types (p. 289) (там же таблица с сравнениями архитектура - тип - размер)

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

Re: чтение-запись данных ядра через /proc

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

Olej писал(а): Не пользуйтесь классификацией "в 1 способе из трёх имеющихся" - я уже давно не понимаю кто из них какой: 1-й, 2-1, 3-й, 4-й... Но я хоть внимательно слежу за темой, а если кто со стороны решит почитать? - да он с ума сойдёт! :twisted:

Или напишите явную квалификацию 1 раз: 1-й способ - это ... , 2-й способ - это ...
Однажды корнет повел поручика в гости к своим знакомым. Поручик увидел там несколько странную картину. Гости сидели за столом.
- Пятнадцатый! - сказал кто-то. Все засмеялись.
- А сорок пятый-то, сорок пятый! - все еще сильнее захохотали.
- Скажите, корнет, чем это они занимаются ? - шепнул поручик.
- Они рассказывают анекдоты. Hо так как давно уже все друг-другу рассказали, то решили пронумеровать их для экономии времени.
- Занятно. - сказал изумленный поручик. - Семдесят четвертый!
Все вдруг смолкли, и одна дама подошла к поручику и дала ему пощечину.
- Поручик! При дамах такие анекдоты не рассказывают! - пояснил корнет.
И опять же по теме :

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

			/*
			 * 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.
			 */
Собственно с программисткой нумерацией...

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

Re: чтение-запись данных ядра через /proc

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

bose писал(а): Ну и далее по делу:
Это не по делу ;-) : то, что можно преобразовывать - это и так понятно (можно было не цитировать).
Непонятна логика, которую они придавали char **start, как они его предполагали использовать...
Зачем в прототипе описывать char** чтоб его всегда преобразовывать в unsigned long?

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

Re: чтение-запись данных ядра через /proc

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

Olej писал(а): Мне это как-то непонятно и странно... off - это входной параметр, который нам передаётся как копия (по значению), который мы можем принять к сведению ... или не принять, но влиять на него никак не можем. Откуда тогда "не всегда"? "может быть"? ... если мы никак не можем влиять на то, что это может быть?
Вы в некоторых вопросах педантичны :-D
Есть определённая логика изменения параметра (т.е. можно предсказать на сколько он увеличиться в следующий раз). Она может менятся в зависимости от....
и потом в коде так и написано:
;-)

Вобщем повсеместно - хаки и эксплойты...
Последний раз редактировалось bose 13 мар 2012, 17:05, всего редактировалось 1 раз.

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

Re: чтение-запись данных ядра через /proc

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

Olej писал(а): Но указатель на указатель - в целое
Olej писал(а): Это не по делу ;-) : то, что можно преобразовывать - это и так понятно (можно было не цитировать).
Ну тогда уже я перестаю понимать вас. Я так понял что вас именно это смутило
Olej писал(а): Зачем в прототипе описывать char** чтоб его всегда преобразовывать в unsigned long
в unsigned long - для удобства пользования (значение, которое лежит по указаному адресу может использоваться и как указатель и как целое (смещение, индекс, щётчик)).

Придираетесь мне кажется вы. :-?

Ответить

Вернуться в «Linux изнутри»

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

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