Как выделить буфер 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;
}

решение: Поскольку функция выше фактически не скомпилирована в ядро, вам нужно будет добавить ее в источник драйвера.

РАБОЧИЙ ПРОЦЕСС НА СТОРОНЕ ПОЛЬЗОВАТЕЛЯ

  1. выделите 1GB hugepages при загрузке с параметрами загрузки ядра
  2. звоните get_huge_pages () с hugetlbfs, чтобы получить указатель пространства пользователя (виртуальный адрес)
  3. передать виртуальный адрес пользователя (обычный указатель на unsigned long) драйверу ioctl

РАБОЧИЙ ПРОЦЕСС ДРАЙВЕРА ЯДРА

  1. принять виртуальный адрес пользователя через ioctl
  2. вызов follow_huge_addr, чтобы получить страницу структуры*
  3. вызовите page_to_phys на странице структуры*, чтобы получить физический адрес
  4. снабдите физический адрес прибор для DMA
  5. вызовите kmap на странице структуры* если вы также хотите виртуальный указатель ядра

отказ от ответственности

  • вышеупомянутые шаги вспоминаются несколько лет спустя. Я потерял доступ к исходному коду. Прояви должную осмотрительность и убедись, что я не забыл один шаг.
  • единственная причина, по которой это работает, заключается в том, что огромные страницы 1GB выделяются во время загрузки, а их физические адреса постоянно заблокированы. Не пытайтесь составить карту виртуальный адрес пользователя без поддержки 1GBhugepage в физический адрес DMA! Ты плохо проведешь время!
  • тщательно проверьте свою систему, чтобы убедиться, что ваши огромные страницы 1GB фактически заблокированы в физической памяти и что все работает точно. Этот код работал безупречно на моей настройке, но здесь есть большая опасность, если что-то пойдет не так.
  • этот код гарантированно работает только на архитектуре x86/x64 (где физический адрес = = адрес Шины) и на ядре версия 2.6.ХХ. Там может быть более простой способ сделать это в более поздних версиях ядра, или это может быть совершенно невозможно.