Как выделить буфер DMA, поддерживаемый 1GB HugePages в модуле ядра linux?
Я пытаюсь выделить буфер DMA для рабочей нагрузки HPC. Для этого требуется 64 ГБ буферного пространства. Между вычислениями некоторые данные выгружаются на карту PCIe. Вместо того, чтобы копировать данные в кучу dinky 4MB буферов, данных pci_alloc_consistent, я хотел бы просто создать 64 1GB буферов, поддерживаемых 1GB HugePages.
справочная информация: версия ядра: в CentOS 6.4 / 2.6.32-358.el6.архитектуру x86_64 параметры загрузки ядра: hugepagesz=1g hugepages=64 default_hugepagesz=1g
соответствующая часть /proc / meminfo: AnonHugePages: 0 kB HugePages_Total: 64 HugePages_Free: 64 HugePages_Rsvd: 0 HugePages_Surp: 0 Hugepagesize: 1048576 КБ DirectMap4k: 848 КБ DirectMap2M: 2062336 КБ DirectMap1G: 132120576 КБ
Я могу установить-t hugetlbfs nodev/mnt / hugepages. CONFIG_HUGETLB_PAGE имеет значение true. Определяется MAP_HUGETLB.
Я прочитал некоторую информацию об использовании libhugetlbfs для вызовите get_huge_pages () в пользовательском пространстве, но в идеале этот буфер будет выделен в пространстве ядра. Я попытался вызвать do_mmap () с помощью MAP_HUGETLB, но это, похоже, не изменило количество бесплатных hugepages, поэтому я не думаю, что он на самом деле поддерживал mmap с огромными страницами.
Так что я думаю, что я имею в виду, есть любой как я могу сопоставить буфер с 1Gb HugePage в пространстве ядра, или это нужно сделать в пространстве пользователя? Или если кто знает другой способ, я могу получить огромный (1-64GB) объем непрерывной физической памяти, доступной в качестве буфера ядра?
2 ответов
это обычно не делается в пространстве ядра, поэтому не слишком много примеров.
Как и любая другая страница, огромные страницы выделяются alloc_pages, чтобы настроить:
struct page *p = alloc_pages(GFP_TRANSHUGE, HPAGE_PMD_ORDER);
HPAGE_PMD_ORDER-это макрос, определяющий порядок одной огромной страницы с точки зрения обычных страниц. Из вышесказанного следует, что в ядре включены прозрачные огромные страницы.
затем вы можете продолжить отображение полученного указателя страницы обычным способом с помощью kmap().
отказ от ответственности: я никогда не пробовал сам, поэтому вам, возможно, придется экспериментировать. Одна вещь, чтобы проверить это: HPAGE_PMD_SHIFT представляет собой порядок меньшей" огромной " страницы. Если вы хотите использовать эти гигантские страницы 1GB, вам, вероятно, нужно будет попробовать другой порядок, вероятно, PUD_SHIFT - PAGE_SHIFT.
глубоко в исходном коде ядра 2.6 лежит эта функция для того чтобы получить страницу структуры от виртуального адреса, маркированного как "как раз для испытывать" и преграженного С #Если 0:
#if 0 /* This is just for testing */
struct page *
follow_huge_addr(struct mm_struct *mm, unsigned long address, int write)
{
unsigned long start = address;
int length = 1;
int nr;
struct page *page;
struct vm_area_struct *vma;
vma = find_vma(mm, addr);
if (!vma || !is_vm_hugetlb_page(vma))
return ERR_PTR(-EINVAL);
pte = huge_pte_offset(mm, address);
/* hugetlb should be locked, and hence, prefaulted */
WARN_ON(!pte || pte_none(*pte));
page = &pte_page(*pte)[vpfn % (HPAGE_SIZE/PAGE_SIZE)];
WARN_ON(!PageHead(page));
return page;
}
решение: Поскольку функция выше фактически не скомпилирована в ядро, вам нужно будет добавить ее в источник драйвера.
РАБОЧИЙ ПРОЦЕСС НА СТОРОНЕ ПОЛЬЗОВАТЕЛЯ
- выделите 1GB hugepages при загрузке с параметрами загрузки ядра
- звоните get_huge_pages () с hugetlbfs, чтобы получить указатель пространства пользователя (виртуальный адрес)
- передать виртуальный адрес пользователя (обычный указатель на unsigned long) драйверу ioctl
РАБОЧИЙ ПРОЦЕСС ДРАЙВЕРА ЯДРА
- принять виртуальный адрес пользователя через ioctl
- вызов follow_huge_addr, чтобы получить страницу структуры*
- вызовите page_to_phys на странице структуры*, чтобы получить физический адрес
- снабдите физический адрес прибор для DMA
- вызовите kmap на странице структуры* если вы также хотите виртуальный указатель ядра
отказ от ответственности
- вышеупомянутые шаги вспоминаются несколько лет спустя. Я потерял доступ к исходному коду. Прояви должную осмотрительность и убедись, что я не забыл один шаг.
- единственная причина, по которой это работает, заключается в том, что огромные страницы 1GB выделяются во время загрузки, а их физические адреса постоянно заблокированы. Не пытайтесь составить карту виртуальный адрес пользователя без поддержки 1GBhugepage в физический адрес DMA! Ты плохо проведешь время!
- тщательно проверьте свою систему, чтобы убедиться, что ваши огромные страницы 1GB фактически заблокированы в физической памяти и что все работает точно. Этот код работал безупречно на моей настройке, но здесь есть большая опасность, если что-то пойдет не так.
- этот код гарантированно работает только на архитектуре x86/x64 (где физический адрес = = адрес Шины) и на ядре версия 2.6.ХХ. Там может быть более простой способ сделать это в более поздних версиях ядра, или это может быть совершенно невозможно.