Вопрос о direct I/O (get_user_pages)
Модератор: Olej
-
- Писатель
- Сообщения: 107
- Зарегистрирован: 23 фев 2012, 14:41
- Откуда: Киев
- Контактная информация:
Вопрос о direct I/O (get_user_pages)
В драйвере есть необходимость доступа к структурам данных процесса пользователя, а имеенно нужно отобразить пользовательскую структуру данных, которая занимает ок 18 Мб, на виртуальные адреса ядра. Для этого в ядрах > 2.6 используется механизм direct I/O (в замен старого kiobuf).
Существует функция get_user_pages, которая и реализовывает этот механизм.
Механизм работы функции таков, что она берёт размер и указатель на виртуальный адрес (внимание) непрервыного!!! пользовательского пространства, и возвращает указатели на страницы физической памяти текущего процесса. Затем в ядре (в драйвере), есть возможность получить (вызовом kmap) виртуальные адресса ядра, указывающие на эти страницы. Есть одно но - отображение не является линейным. Т.е. в ядре пользовательская структура данных (которая, повторюсь, непрерывна в виртуальном адрессном пространстве процесса) разбивается на куски размером в PAGE_SIZE, которые в виртуальном адрессном пространстве ядра находятся разрозненно! По сути вопрос - как "склеить" эти куски, что бы в ядре можно было работать с указателем на структуру данных, а не участками данных размером в страницу.
Существует функция get_user_pages, которая и реализовывает этот механизм.
Механизм работы функции таков, что она берёт размер и указатель на виртуальный адрес (внимание) непрервыного!!! пользовательского пространства, и возвращает указатели на страницы физической памяти текущего процесса. Затем в ядре (в драйвере), есть возможность получить (вызовом kmap) виртуальные адресса ядра, указывающие на эти страницы. Есть одно но - отображение не является линейным. Т.е. в ядре пользовательская структура данных (которая, повторюсь, непрерывна в виртуальном адрессном пространстве процесса) разбивается на куски размером в PAGE_SIZE, которые в виртуальном адрессном пространстве ядра находятся разрозненно! По сути вопрос - как "склеить" эти куски, что бы в ядре можно было работать с указателем на структуру данных, а не участками данных размером в страницу.
- Olej
- Писатель
- Сообщения: 21338
- Зарегистрирован: 24 сен 2011, 14:22
- Откуда: Харьков
- Контактная информация:
Re: Вопрос о direct I/O (get_user_pages)
Как всегда в подобных случаях ответ на этот вопрос начинается с другого вопроса :bose писал(а):По сути вопрос - как "склеить" эти куски, что бы в ядре можно было работать с указателем на структуру данных, а не участками данных размером в страницу.
- как сформулировать тестовую задачу, моделирующую эту ситуацию?
- и написать демонстрационный проект ... да ещё и как можно проще, чтобы не загружать лишними подробностями.
-
- Писатель
- Сообщения: 107
- Зарегистрирован: 23 фев 2012, 14:41
- Откуда: Киев
- Контактная информация:
Re: Вопрос о direct I/O (get_user_pages)
Я не достаточно подробно описал проблему?Olej писал(а): Как всегда в подобных случаях ответ на этот вопрос начинается с другого вопроса :
Более обобщённо - как отобразить непрерывный диапазон виртуальных адресов пользовательского процесса, на непрерывный диапазон виртуальных адресов ядра такого же размера?
У меня есть модуль, который в паре с пользовательским ПО воспроизводит проблему (тестовым я его конечно не назову), и я могу его выложить (после небольшого редактирования - чтобы не загружать лишними подробностями )... но данный вопрос скорее не практический (покажитке как), а концептуальный (существует ли такая возможность)... Т.е. сталкивался кто-то с подобным вопросом или нет...Olej писал(а): - как сформулировать тестовую задачу, моделирующую эту ситуацию?
- и написать демонстрационный проект ... да ещё и как можно проще, чтобы не загружать лишними подробностями.
- Olej
- Писатель
- Сообщения: 21338
- Зарегистрирован: 24 сен 2011, 14:22
- Откуда: Харьков
- Контактная информация:
Re: Вопрос о direct I/O (get_user_pages)
Вот об этом и речь ... только не небольшое редактирование, а как можно большее , чтобы оставить только суть проблемы.bose писал(а): У меня есть модуль, который в паре с пользовательским ПО воспроизводит проблему (тестовым я его конечно не назову), и я могу его выложить (после небольшого редактирования - чтобы не загружать лишними подробностями )...
А никто вам "концептуально" не скажет вот так на пальцах, без кода ... разве что 1-2-3 непосредственных разработчиков кода этого места в ядре ... - но это если вы их разыщитеbose писал(а): но данный вопрос скорее не практический (покажитке как), а концептуальный (существует ли такая возможность)... Т.е. сталкивался кто-то с подобным вопросом или нет...
-
- Писатель
- Сообщения: 107
- Зарегистрирован: 23 фев 2012, 14:41
- Откуда: Киев
- Контактная информация:
Re: Вопрос о direct I/O (get_user_pages)
Ну вот, аттачу драйвер и пользовательское приложение, которые в паре позволяют показать проблему...
Как всегда:
, и далее:
Собственно на что нужно обратить внимание... - несмотря на то что в драйвере мы корректно (последовательно, страница за страницей) получили доступ к всему содержимому пользовательского буфера, виртуальные адреса пространства ядра, указывающие на отдельные страницы внутри пользовательского буфера (получили вызовом kmap), не являются последовательными....
Выхлоп dmesg |tail -n 5 на моём десктопе (Linux 3.2.0-39-generic x86_64):
Как всегда:
Код: Выделить всё
make
sudo make install
Код: Выделить всё
./devtest
dmesg |tail -n 5
Выхлоп dmesg |tail -n 5 на моём десктопе (Linux 3.2.0-39-generic x86_64):
Например:[30273.676525] ioctl: succes pin 4 pages ( user address: 2229000 ).
[30273.676532] Request: 4096; Read: 4096; Offset: 0; Vaddress: 0xffff88011a22c000;
[30273.676574] Request: 4096; Read: 4096; Offset: 4096; Vaddress: 0xffff88011a23a000;
[30273.676623] Request: 4096; Read: 4096; Offset: 8192; Vaddress: 0xffff8801184a9000;
[30273.678308] Request: 4096; Read: 4096; Offset: 12288; Vaddress: 0xffff88011a235000;
Коряво псевдографикой:$ python -c 'print 0xffff88011a23a000-0xffff88011a22c000'
57344 - ожидаю 4096
$ python -c 'print 0xffff8801184a9000-0xffff88011a23a000'
-31002624 - опять ожидаю 4096
User Space VA | Kernel Space VA
|P1|P2|P3|P4| -> |P3|...|P2|..|P1|P4|
- Вложения
-
- directio.tgz
- Модуль псевдосимвольного устр-ва usrdev
- (3.35 КБ) 382 скачивания
- Olej
- Писатель
- Сообщения: 21338
- Зарегистрирован: 24 сен 2011, 14:22
- Откуда: Харьков
- Контактная информация:
Re: Вопрос о direct I/O (get_user_pages)
По первому взгляду ... по-верхам:bose писал(а): Собственно на что нужно обратить внимание... - несмотря на то что в драйвере мы корректно (последовательно, страница за страницей) получили доступ к всему содержимому пользовательского буфера, виртуальные адреса пространства ядра, указывающие на отдельные страницы внутри пользовательского буфера (получили вызовом kmap), не являются последовательными....
1. Как я понимаю, страницы буфера и не должны отображаться последовательно, потому что страницы эти выделяются в физической RAM по произвольным, далеко не последовательным ядресам. Это происходит когда ваш вызов memalign() в пользовательском приложении devtest.c ретранслируется в системный вызов, по которому ядро и выделит RAM вашему приложению, и как я понимаю, выделит её вызовом vmalloc(), а не kmalloc(). А уже приложению devtest.c эти страницы RAM через таблицы MMU будут отображены в последовательные логические адреса.
2. Если хотелось бы последовательного отображения я ядерном пространстве, то, наверное, нужно было бы добиться, чтобы буфер выделялся в непрерывной физической области RAM, вызовом типа kmalloc()?
3. А зачем вам непрерывное отображение? Я думаю, для копирования данных единым оператором копирования (типа memcpy()).
- а сильно существенна ли разница?
- выделяя непрерывную область (в физической RAM) этого можно было бы, возможно, добиться...
- или организовывать передачу данных операциями по типу векторного ввода-вывода ... такие операции копирования между памятью есть в ядре, я их видел и использовал в примерах драйверов блочных устройств (в первоначальном тексте этого не было, но добавлено позже, см. http://mylinuxprog.blogspot.com/2013/01/linux.html)
4. ... это уже не относится к существу дела, но по коду приложения devtest.c (драйвер я ещё не успел пересмотреть):
4.1. вызов getpagesize() считают устаревшим и непереносимым ... об этом пишет и man getpagesize(2) - согласно нему строку:
Код: Выделить всё
const unsigned long psize = (unsigned long) getpagesize();
Код: Выделить всё
const unsigned long psize = sysconf( _SC_PAGESIZE );
Код: Выделить всё
pbuffer = (void *) memalign( psize, PAGE_COUNT * psize );
Код: Выделить всё
pbuffer = valloc( PAGE_COUNT * psize );
- Olej
- Писатель
- Сообщения: 21338
- Зарегистрирован: 24 сен 2011, 14:22
- Откуда: Харьков
- Контактная информация:
Re: Вопрос о direct I/O (get_user_pages)
bose, вы где-то намудрячили, когда готовили пример (а перед отправкой его не проверили):bose писал(а):Ну вот, аттачу драйвер и пользовательское приложение, которые в паре позволяют показать проблему...
Как всегда:, и далее:Код: Выделить всё
make sudo make install
Код: Выделить всё
./devtest dmesg |tail -n 5
Код: Выделить всё
bash-4.2$ sudo insmod usrdev.ko
bash-4.2$ dmesg | tail -n1
[36962.035502] Device userdev registred.
bash-4.2$ lsmod | head -n2
Module Size Used by
usrdev 12673 0
Код: Выделить всё
bash-4.2$ ./devtest
Start buffer 0x9219000.
Problem opening the node /dev/usrdev: No such file or directory.
bash-4.2$ ls /dev/usr*
ls: невозможно получить доступ к /dev/usr*: Нет такого файла или каталога
-
- Писатель
- Сообщения: 107
- Зарегистрирован: 23 фев 2012, 14:41
- Откуда: Киев
- Контактная информация:
Re: Вопрос о direct I/O (get_user_pages)
На самом деле буфер в пользовательском пространстве в данном случае абстракция... в реальности там находиться структура данных, со своими полями, которые в свою очередь также являются составными типами данных + массивы... эти поля и масивы, понятное дело, не выравнены на границы страниц...Olej писал(а): 3. А зачем вам непрерывное отображение? Я думаю, для копирования данных единым оператором копирования (типа memcpy()).
Пользовательское приложение заполняет и периодически модифицирует эти данные, драйвер должен принимать во внимание эти изменения...
Т.е. драйверу удобно работать не с сырым буфером, а со структурой... она большая ок. 24 Мб.
Вроде того:
Код: Выделить всё
struct VeryBigStructure;
struct VeryBigStructure * pvbs = (struct VeryBigStructure *) kmap( pages[0] );
treshold = pvbs->tooFarThan4096bytes;
и потом mmap - занят для других нужд
Исключительно для нужд данного примера, дальше это никуда не пойдёт... getpagesize - более красноричивей поясняет что я хотел сделать...Olej писал(а): 4.1. вызов getpagesize() считают устаревшим и непереносимым ... об этом пишет и man getpagesize(2) - согласно нему строку:лучше заменить на:Код: Выделить всё
const unsigned long psize = (unsigned long) getpagesize();
Код: Выделить всё
const unsigned long psize = sysconf( _SC_PAGESIZE );
из того же мана:Olej писал(а): 4.2. опять же (man memalign(3))поменять на:Код: Выделить всё
pbuffer = (void *) memalign( psize, PAGE_COUNT * psize );
Код: Выделить всё
pbuffer = valloc( PAGE_COUNT * psize );
А вообще, маны предмет отдельного обсуждения... притензий много... в них пишут как на заборах, содержимое обновляют редко...The obsolete function memalign()...
The obsolete function valloc()...
а как известно устаревшая информаця хуже её отсутсвия...
Вообще пользовался функцией posix_memalign
В мане сказано...
Но самый простецкий пример с выделением и последующим освобождением памяти этой функцией приводит к double free or corruptionPOSIX requires that memory obtained from posix_memalign() can be freed using free(3).
-
- Писатель
- Сообщения: 107
- Зарегистрирован: 23 фев 2012, 14:41
- Откуда: Киев
- Контактная информация:
Re: Вопрос о direct I/O (get_user_pages)
Олег, я не создаю ноду в коде... если посмотрите makefile то увидите там в цели installOlej писал(а): Модуль usrdev.ko вовсе не создаёт имени /dev/usrdev, которое ожидает получить devtest (да и символьные эти имена записаны явно в текстах devtest.c и userdev.c ... вместо того, чтобы определяться согласованно один раз в utok.h).
я же написал...
Это не методический пример, и потом мы же договорились не перегружать код дабы не уходить от вопроса... только то что нужно что бы осветить вопросsudo make install
- Olej
- Писатель
- Сообщения: 21338
- Зарегистрирован: 24 сен 2011, 14:22
- Откуда: Харьков
- Контактная информация:
Re: Вопрос о direct I/O (get_user_pages)
Не досмотрел (mknod и т.д.)bose писал(а):Олег, я не создаю ноду в коде... если посмотрите makefile то увидите там в цели installOlej писал(а): Модуль usrdev.ko вовсе не создаёт имени /dev/usrdev, которое ожидает получить devtest (да и символьные эти имена записаны явно в текстах devtest.c и userdev.c ... вместо того, чтобы определяться согласованно один раз в utok.h).
я же написал...Это не методический пример, и потом мы же договорились не перегружать код дабы не уходить от вопроса... только то что нужно что бы осветить вопросsudo make install
Я очень боюсь всяких sudo, и sudo make install, и действий от root, которые выполняются из чужого кода - никогда не делаю
Кто сейчас на конференции
Сейчас этот форум просматривают: нет зарегистрированных пользователей и 2 гостя