LINUX.ORG.RU

вопрос о get_usr_pages()


0

1

В приложении пространстве пользователя выделяется большой объем памяти, 128 Мб и более. Необходимо получить физические адреса всех страниц этой памяти для формирования DMA буфера. Адрес буфера пользователя передается в модуль ядра в функцию get_user_pages():

  int	 n_pages = 0;
  struct page** locked_pages = kmalloc(
         (userSpaceSize/PAGE_SIZE)*sizeof(struct page*),
         GFP_KERNEL));
 
  down_read(&current->mm->mmap_sem);
  n_pages = get_user_pages(current, 
			  current->mm,
			  userSpaceAddress,
			  (userSpaceSize/PAGE_SIZE),
			  1, 
			  0,
			  locked_pages, NULL);
  up_read(&current->mm->mmap_sem);
функция выолняется без ошибок и возвращает необходимое число страниц. Когда начинаю смотреть содержимое буфера locked_pages, то там во всех элементах один и тот же указатель хранится.

for(i=0; i<n_pages; i++) {
    printk("<0>%s - %s(): page[%d] = %p\n", 
           DRVNAME, __FUNCTION__, i,              
           locked_pages[i]);
}

log при userSpaceSize = 0x4000: (при больших размерах результат такой же)

UserMemoryLock(): Lock 4 memory pages
UserMemoryLock(): page[0] = c17625e0
UserMemoryLock(): page[1] = c17625e0
UserMemoryLock(): page[2] = c17625e0
UserMemoryLock(): page[3] = c17625e0
Подскажите почему адреса в locked_pages все одинаковые? Может я неправильно применил get_user_pages(). Просто непонятно что делать дальше с «таким» результатом. Спасибо.


struct page** locked_pages = kmalloc( (userSpaceSize/PAGE_SIZE)*sizeof(struct page*), GFP_KERNEL));

Что-то это «**» кажется подозрительным.

tailgunner ★★★★★
()
Ответ на: комментарий от tailgunner

Угу, похоже, что в итоге он печатает собственный адрес

TERRANZ ★★★★
()
Ответ на: комментарий от tailgunner

> Хотя вроде всё правильно, кроме вычисления числа страниц... А как правильно?

karak
() автор топика
Ответ на: комментарий от karak

Проблема разрешилась. Если парметр write == 0, у get_user_pages() то адреса страниц одинаковые, если же write == 1 - то отличаются. Извиняюсь, что ввел в заблуждение псевдокодом. Остался один вопрос с определением len = (userSpaceSize/PAGE_SIZE). Подскажите, как это сделать более правильно м.б. get_order(userSpaceSize)?

P.S. В приложении память всегда выровнена и размер кратен размеру страницы, так сказать частный случай.

karak
() автор топика

По-моему, шиворот на выворот сделано. Для такого размера буфера неплохо бы memmap в kernel cmdline подсунуть, чисто для того, чтобы буфер всегда можно было иметь. Потом буфер ммапится в mm юзерского процесса. В ldd что-то такое есть, iirc.

mv ★★★★★
()
Ответ на: комментарий от mv

> По-моему, шиворот на выворот сделано.

А по-моему, нормально.

Для такого размера буфера неплохо бы memmap в kernel cmdline подсунуть

Для 4 страниц? %)

tailgunner ★★★★★
()
Ответ на: комментарий от karak

> P.S. В приложении память всегда выровнена и размер кратен размеру страницы, так сказать частный случай.

Драйвер не имеет права расчитывать на это. Если приложение ошибется, он будет глючить молча.

tailgunner ★★★★★
()
Ответ на: комментарий от tailgunner

Для 4 страниц? %)

В приложении пространстве пользователя выделяется большой объем памяти, 128 Мб и более. Необходимо получить физические адреса всех страниц этой памяти для формирования DMA буфера.

У вас страницы по 32 мегабайта?

mv ★★★★★
()
Ответ на: комментарий от mv

> У вас страницы по 32 мегабайта?

Нет, по 4. Но вроде не сказано, что DMA-транзакция будет одновременно во все. Впрочем, даже если и будет, то при наличии в устройстве поддержки s/g я бы не морочился с командной строкой ядра.

tailgunner ★★★★★
()
Ответ на: комментарий от tailgunner

Устройство как раз s/g поддерживает. А памяти может выделяться и больше. В текущей реализации, когда память выделяется в пространстве ядра модулем и затем mmap в приложении. Может кому пригодится, привожу результаты:

Общее количество физической памяти: 2 Гб Размер выделяемого блока физически непрерывной памяти: 4 Мб

Для Linux х32

Максимум 250 х 4 Мб (система еле дышит) Оптимально 190 х 4 Мб (нормально работает) Общий объем выделенной памяти: 760 Мб

Для Linux х64 (тот же комп)

Максимум 387 х 4 Мб Оптимально 340 х 4 Мб Общий объем выделенной памяти: 1360 Мб

Использовать get_user_page() пока не успел.

karak
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.