LINUX.ORG.RU

Выделение памяти в модуле ядра


0

0

Задача такая: модуль выделяет память и руализует вызов mmap для отображения этой памяти в пространство пользователя. Модуль писался в соответствии с примерами Рубини. Работает он следующим образом: 1. Памяти выделяется в init_module с помощью <адрес> = __get_free_pages(GFP_KERNEL, 4); 2. Память освобождается в cleanup_module с помощью free_pages(<адрес>); 3. В реализации nopage в конце вызывается get_page(<page>);

При этом происходят не понятные вещи: 1. При выделении нескольких страниц счетчик использования равен 1 только для первой страницы, для оствльеых - 0. Посмотрел реализацию процедуры выделения - действительно, только для первой страницы. Почему? 2. При выгрузке модуля выделенная память назаж не возвращается - проверял с помощью утилиты free 3. После обращения пользователя к выделенным страницам, выгрузке модуля и повторной загрузке система палает намертво. При этом, если при выдалении принудительно сделать get_page на все страницы, кроме первой - этого не происходит.

Кто может, объясните, pliz, почему так происходит и в чем я не прав?

мож лучше использовать kmalloc() и vmalloc()?

anonymous
()

В вопросе половина ответа.

get_free_pages возвращает кусок памяти, которую
vm рассматривает как одно целое, поэтому и счетчик
взводится только для первой страницы. Освободить
их можно только все сразу.

nopage() вызывает get_page() и увелисивает count, это
правильно. Но! когда процесс делает unmap(), zap_pte_range()
уменьшит счетчик для каждой страницы. Т.к. он станет
равным 0 (кроме первой), vm посчитает страницу свободной,
и попытается освободить ее. Здесь уже вполне возможен
крах. Я не помню сейчас, по-моему в 2.6 там есть проверочка,
которая что-то напишет в syslog.

Что делать. Действительно, можно после получения памяти
сделать всем кроме первой страницы get_page(),
в cleanup_module(), соответственно, put_page(),
а потом уже free_pages().

Можно поставить всем страницам PageReserved флаг,
тогда vm вообще не будет их трогать. Это, кстати,
и по другим причинам хорошая идея.

Можно выделить необходимое количество страниц по одной,
тогда у каждой вначале count == 1. Поэтому совет про vmalloc()
хоть и неправильный (по другим причинам :) сработает:
vmalloc() именно так и делает.

kmalloc здесь, понятно, никак не годится.

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

можешь рассказать почему vmalloc() не правильный, а kmalloc я так понимаю выделяет реальную память и если, напримаер тебе нужно, чтобы дма в него писал, то ее и надо использовать, если нет объясни, пожалуйста, почему.

автор поста про кmalloc и вмаллок.

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

автору поста про кmalloc и вмаллок:

> можешь рассказать почему vmalloc() не правильный,

Вообще-то, приношу извинения, писал второпях, он где-то
и правильный, я ведь сказал, что работать будет. Но vmalloc()
_значительно_ более дорогая функция, она модифицирует init_mm,
требует дополнительно памяти, для vm_struct, для pte entries,
адресное пространство VMALLOC_START-VMALLOC_END ограниченно,
доступ к этой памяти (в ядре) будет чуть медленнее из-за лишней
нагрузки на tlb и cpu кэш.

Кроме того, в nopage() понадобятся дополнительные усилия:
vmalloc_to_page() - не помню точно, как оно зовется.

vmalloc() нужен когда нам требуется большой логически (не физически)
непрерывный кусок памяти, который мы не можем получить с помощью
__get_free_pages().

> а kmalloc я так понимаю выделяет реальную память и если,
> напримаер тебе нужно, чтобы дма в него писал, то ее и надо использовать

Опять же, зря я написал что "никак не годится".
что значит "реальную память", я не понимаю. Но get_free_pages()
вернет память реальную не менее и пригодную для dma в той же степени.
Хотя бы потому, что slab allocator в конечном итоге вызывает
все ту же get_free_pages().

Имелось в виду, что никаких проблем с page->count kmalloc() не решит.
Использовать ее в данном случае не очень уместно, т.к. она
опять-таки сложнее, делает больше, и никаких преимуществ (в данном
случае) не дает.

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

нет, ну kmalloc возвращает адрес на память, котроая стоит на мат.плате, а вмаллок на вирыуальную, правильно? грубо, но типа, чтобы быть уверенным. и есть ли смысл звать get_free_pages() или в некоторых случаюх можно обойтись и vmalloc i malloc?

anonymous
()
Ответ на: комментарий от idle

вопросов :)

1. Как правильно освобождать память, выделенную через get_fre_pages? Судя по показаниям утил. free, после выгрузки модуля пямяти больше не становится, что без PG_reserved, что с PG_reserved, все-равно. Кстати, free_pages не выполняется, если этот флаг установлен.

2. > Можно поставить всем страницам PageReserved флаг,

> тогда vm вообще не будет их трогать. Это, кстати, > и по другим причинам хорошая идея.

По каким причинам? Неучастие в свопировании?

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

> Как правильно освобождать память, выделенную через get_fre_pages?

free_pages(). В cleaunup_module() page->count должен быть == 1 для
первой страницы, для остальных 0. Если мы в init_module() делали
get_page() (как я писал в первом ответе), то тоже 1, и надо опустить
его до нуля. Только не надо, конечно же, делать put_page() - это
я сгоряча написал :) - это приведет к попытке освободить одну эту
страницу, тк после уменьшения счетчика там будет 0 и приехали.
Надо руками: atomic_dec(page->count).

Лично я бы все-таки аллокировал требуемое количество страниц
по одной штучке.

> Кстати, free_pages не выполняется, если этот флаг установлен.

Конечно, его нужно снять в cleanup_module() и не только по этой
причине.

> По каким причинам? Неучастие в свопировании?

Эти страницы и так не могут быть свопнуты. Точнее, vm может
попытаться это сделать, если мы не будем играться с page->count
или выставлять PG_reserved, ничего хорошего из этого не выйдет.

В случае, если мы поставим это флажок всем страницам, vm
не будет изменять/проверять page->count, тогда в nopage()
даже не надо делать get_page(). Кроме того, эти страницы
не будут фигурировать в active/inactive lists, для них
не будет rmap, да много чего...

grep -r PageReserved /path_to_kernel_src покажет много интересного.

> нет, ну kmalloc возвращает адрес на память, котроая стоит на мат.плате,
> а вмаллок на вирыуальную, правильно?

Ну как это может быть правильно? Любая память на мат.плате стоит,
и адрес в любом случае "виртуальный".

Но в предыдущем ответе я сравнивал kmalloc и get_free_pages.

> и есть ли смысл звать get_free_pages() или в некоторых случаюх можно
> обойтись и vmalloc i malloc?

Ох... я бы сказал, что в некоторых случаях трудно обойтись без vmalloc.
malloc() вообще не существует.

Серьезно, не знаю как правильно и коротко обьяснить. Знал бы - писал
бы книжки. Ну почитайте Rubini, я когда-то ее просматривал, по-моему
очень толковая.

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

да ладно! фигня, главное чтоб работало, а остальное...

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