2013-10-18 4 views
8

Ich versuche, einen DMA-Puffer für eine HPC-Arbeitslast zuzuordnen. Es benötigt 64 GB Pufferspeicher. Zwischen der Berechnung werden einige Daten auf eine PCIe-Karte ausgelagert. Anstatt Daten in eine Reihe von dinky 4MB Puffern zu kopieren, die von pci_alloc_consistent vergeben werden, möchte ich nur 64 1GB Puffer erstellen, die von 1GB HugePages unterstützt werden.Wie ordne ich einen DMA-Puffer, der von 1GB HugePages unterstützt wird, in einem Linux-Kernelmodul zu?

Einige Hintergrundinfo: Kernel-Version: Optionen CentOS 6.4/2.6.32-358.el6.x86_64 Kernel-Boot: hugepagesz = 1g hugepages = 64 default_hugepagesz = 1g

relevanten Teil von/proc/meminfo: AnonHugePages: 0 kB HugePages_Total: 64 HugePages_Free: 64 HugePages_Rsvd: 0 HugePages_Surp: 0 Hugepagesize: 1048576 kB DirectMap4k: 848 kB DirectMap2M: 2.062.336 kB DirectMap1G: 132.120.576 kB

Ich kann mount -t hugetlbfs nodev/mnt/hugepages. CONFIG_HUGETLB_PAGE ist wahr. MAP_HUGETLB ist definiert.

Ich habe einige Informationen über die Verwendung von libhugetlbfs gelesen, um get_huge_pages() im Benutzerbereich aufzurufen, aber idealerweise würde dieser Puffer im Kernelraum zugewiesen werden. Ich habe versucht, do_mmap() mit MAP_HUGETLB aufzurufen, aber es schien nicht die Anzahl der freien hugepages zu ändern, also glaube ich nicht, dass es die mmap mit riesigen Seiten unterstützt.

Also ich denke, was ich bekomme, gibt es beliebig Weise kann ich einen Puffer auf eine 1GB HugePage im Kernelraum zuordnen, oder muss es in Benutzerraum getan werden? Oder wenn jemand eine andere Möglichkeit kennt, kann ich einen riesigen (1 - 64 GB) zusammenhängenden physischen Speicher als Kernel-Puffer zur Verfügung stellen?

+0

Interessante Frage, ist Ihr Ziel vor allem zu vermeiden, Kopieren zwischen Kernel-und User-Space? – ChuckCottrill

+2

Alle diese APIs sind für den Benutzerraum. Sehen Sie sich an, wie hugetlbfs implementiert ist, insbesondere 'hugetlbfs_file_mmap'. –

+0

@muusbolla Konnten Sie die Antwort finden? –

Antwort

1

PROBLEM

  1. Normalerweise mit physikalischen Adressen vertrödeln, wenn Sie einen DMA-Puffer zugewiesen werden sollen, oder eine physikalische Adresse erhalten, dies im Kernel-Raum durchgeführt wird, wie Code Benutzer soll sich nie.
  2. hugetlbfs bietet nur User-Space-Mappings 1 GB große Seiten zuzuordnen, und erhalten User-Space virtuelle Adressen
  3. Keine Funktion

EUREKA

einen Benutzer hugepage virtuelle Adresse in eine physikalische Adresse zur Karte vorhanden

Aber die Funktion existiert! Begraben deep in the 2.6 kernel source code liegt diese Funktion eine Struktur von einer virtuellen Adresse zu erhalten, die als „nur zum Testen“ und blockiert mit # if 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; 
} 

LÖSUNG: Da die Funktion oben ist nicht wirklich in die kompilierte Kernel, müssen Sie es zu Ihrer Treiberquelle hinzufügen.

USER SIDE WORKFLOW

  1. 1gb hugepages mit Kernel-Boot-Optionen zuweisen
  2. beim Booten
  3. Anruf get_huge_pages() mit hugetlbfs User-Space-Zeiger (virtuelle Adresse)
  4. Pass Benutzer virtuelle Adresse (normale Zeiger zu erhalten gieße unsigned long) an den Treiber ioctl

KERNEL DRIVER ARBEITSABLAUF

  1. Accept Benutzer virtuelle Adresse über ioctl
  2. Anruf follow_huge_addr die struct page *
  3. Anruf page_to_phys auf der struct Seite erhalten * Die physikalische Adresse für die DMA
  4. Geben physikalische Adresse Gerät bekommen
  5. Anruf kmap auf der struct page * wenn Sie auch einen Kernel virtuellen Zeiger

HAFTUNGSAUSSCHLUSS

wollen
  • Die oben genannten Schritte werden einige Jahre später wiederholt. Ich habe den Zugriff auf den ursprünglichen Quellcode verloren. Machen Sie Ihre Sorgfaltspflicht und stellen Sie sicher, dass ich keinen Schritt vergesse.
  • Der einzige Grund dafür ist, dass 1GB große Seiten beim Booten zugewiesen werden und ihre physikalischen Adressen permanent gesperrt sind. Versuchen Sie nicht, eine virtuelle Adresse, die nicht von 1GBhugepage gesichert wurde, einer physischen DMA-Adresse zuzuordnen! Du wirst eine schlimme Zeit haben!
  • Testen Sie sorgfältig auf Ihrem System, um zu bestätigen, dass Ihre 1 GB großen Seiten tatsächlich im physischen Speicher gespeichert sind und alles genau funktioniert. Dieser Code funktionierte einwandfrei auf meinem Setup, aber hier besteht große Gefahr, wenn etwas schief geht.
  • Dieser Code wird nur für die x86/x64-Architektur (physische Adresse == Busadresse) und für die Kernelversion 2.6.XX garantiert. Es kann einen leichteren Weg geben, dies bei späteren Kernel-Versionen zu tun, oder es kann jetzt völlig unmöglich sein.
2

Dieser nicht allgemein im Kernraum getan, so dass nicht zu viele Beispiele.

Genau wie jede andere Seite werden große Seiten mit alloc_pages zugewiesen, nach der Melodie:

struct page *p = alloc_pages(GFP_TRANSHUGE, HPAGE_PMD_ORDER); 

HPAGE_PMD_ORDER ein Makro ist, in Bezug auf den normalen Seiten einen Auftrag von einer einzigen großen Seite definieren. Das bedeutet, dass transparente große Seiten im Kernel aktiviert sind.

Dann können Sie die erhaltenen Seitenzeiger auf die übliche Art und Weise mit kmap gehen Abbildung().

Haftungsausschluss: Ich habe versucht, es mir nie, so können Sie etwas experimentieren um zu tun haben. Eine Sache, auf die Sie achten sollten, ist folgende: HPAGE_PMD_SHIFT repräsentiert eine Reihenfolge einer kleineren "großen" Seite. Wenn Sie diese riesigen 1GB-Seiten verwenden möchten, müssen Sie wahrscheinlich eine andere Reihenfolge versuchen, wahrscheinlich PUD_SHIFT - PAGE_SHIFT.

+1

Werden transparente große Seiten für 1 GB Seiten unterstützt? – osgx

Verwandte Themen