В чем разница между vmalloc и kmalloc?

Я googled вокруг и нашел большинство людей, выступающих за использование kmalloc, так как вы гарантированно получите смежные физические блоки памяти. Однако также кажется, что kmalloc может выйти из строя, если не удается найти непрерывный физический блок.
Каковы преимущества наличия непрерывного блока памяти? В частности, зачем мне нужно иметь непрерывный блок физический в системном вызове? Есть ли причина, по которой я не мог просто использовать vmalloc?
Наконец, если я должен был выделить память во время обработки системного вызова, следует ли указывать GFP_ATOMIC? Является ли системный вызов выполненным в атомном контексте?

GFP_ATOMIC
Распределение является приоритетным и не спит. Это флаг использовать в обработчиках прерываний, снизу половинки и другие ситуации, когда вы не может спать.

GFP_KERNELЭто нормальное распределение и может блокироваться. Это флаг для использования в коде контекста процесса, когда безопасно спать.

Ответ 1

Вам нужно только беспокоиться об использовании физически смежной памяти, если к буферу будет обращаться устройство DMA на физически адресуемой шине (например, PCI). Беда в том, что многие системные вызовы не имеют возможности узнать, будет ли их буфер в конечном итоге передан на устройство DMA: после того, как вы передадите буфер другой подсистеме ядра, вы действительно не можете знать, куда он будет идти. Даже если ядро ​​не использует буфер для DMA сегодня,, это может сделать будущая разработка.

vmalloc часто медленнее, чем kmalloc, потому что ему может потребоваться переназначить буферное пространство в практически непрерывный диапазон. kmalloc никогда не переназначает, хотя если не вызывается с GFP_ATOMIC, то kmalloc может блокировать.

kmalloc ограничен размером буфера, который он может предоставить: 128 Кбайт *). Если вам нужен действительно большой буфер, вам нужно использовать vmalloc или какой-либо другой механизм, например, резервировать высокую память при загрузке.

*) Это справедливо для ранних ядер. В последних ядрах (я тестировал это на 2.6.33.2) максимальный размер одного километрала до 4 МБ! (Я написал довольно подробно подробный пост в этом.) — kaiwan

Для системного вызова вам не нужно передавать GFP_ATOMIC в kmalloc(), вы можете использовать GFP_KERNEL. Вы не обработчик прерываний: код приложения вводит контекст ядра с помощью ловушки, это не прерывание.

Ответ 2

Короткий ответ: загрузите Драйверы устройств Linux и прочитайте главу об управлении памятью.

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

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

Ответ 3

Linux Kernel Development от Robert Love (глава 12, стр. 244 в 3-м издании) отвечает на это очень четко.

Да, физически непрерывная память не требуется во многих случаях. Основной причиной использования kmalloc больше, чем vmalloc в ядре, является производительность. В книге объясняется, что, когда большие куски памяти выделяются с помощью vmalloc, ядро ​​должно отображать физически несмежные куски (страницы) в единую непрерывную область виртуальной памяти. Поскольку память является практически непрерывной и физически несмежной, в таблицу страниц должно быть добавлено несколько сопоставлений между виртуальными и физическими адресами. И в худшем случае будет (размер буфера/размер страницы) количество отображений, добавленных в таблицу страниц.

Это также добавляет давление на TLB (записи кэша, хранящие последние сопоставления виртуальных на физические адреса) при доступе к этому буферу. Это может привести к thrashing.

Ответ 4

В чем преимущества наличия непрерывного блока памяти? В частности, почему мне нужно иметь непрерывный физический блок памяти в системном вызове? Есть ли причина, по которой я не мог просто использовать vmalloc?

От Google "Я чувствую себя счастливым" на vmalloc:

kmalloc является предпочтительным способом, если вам не нужны очень большие области. Проблема в том, что если вы хотите сделать DMA с/на какое-то аппаратное устройство, вам нужно будет использовать kmalloc, и вам, вероятно, понадобится больший кусок. Решение состоит в том, чтобы как можно скорее выделить память память фрагментируется.

Ответ 5

Функции kmalloc() и vmalloc() - это простой интерфейс для получения памяти ядра в блоках размера байта.

  • Функция kmalloc() гарантирует, что страницы физически смежны (и практически смежны).

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

Ответ 6

Одним из других отличий является то, что kmalloc вернет логический адрес (иначе вы укажете GPF_HIGHMEM). Логические адреса помещаются в "низкую память" (в первом гигабайте физической памяти) и отображаются непосредственно на физические адреса (используйте макрос __pa для его преобразования). Это свойство подразумевает, что память в километрах - это непрерывная память.

В другой руке Vmalloc может возвращать виртуальные адреса из "высокой памяти". Эти адреса не могут быть преобразованы в физические адреса напрямую (вы должны использовать функцию virt_to_page).

Ответ 7

В 32-битной системе kmalloc() возвращает логический адрес ядра (его виртуальный адрес), который имеет прямое сопоставление (фактически с постоянным смещением) по физическому адресу. Это прямое отображение гарантирует, что мы получим смежный физический кусок ОЗУ. Подходит для DMA, где мы даем только начальный указатель и ожидаем последующего физического отображения для нашей операции.

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