Wie ordne ich einen DMA-Puffer, der von 1GB HugePages unterstützt wird, in einem Linux-Kernelmodul zu?

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.

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

relevanter Teil von / proc / meminfo: AnonHugeSeiten: 0 kB HugePages_Total: 64 HugePages_Free: 64 HugePages_Rsvd: 0 HugePages_Surp: 0 Riesenseitengröße: 1048576 kB DirectMap4k: 848 kB DirectMap2M: 2062336 kB DirectMap1G: 132120576 kB

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

Ich habe einige Informationen über die Verwendung von libhugetlbfs gelesen, um get_huge_pages () im Userspace 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 tatsächlich die mmap mit riesigen Seiten unterstützt.

Ich schätze, worauf ich hinaus will, gibt es any Weise, wie ich einen Puffer zu einer 1GB HugePage im Kernel-Space zuordnen kann, oder muss es im Userspace gemacht 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?

    
muusbolla 18.10.2013, 23:27
quelle

2 Antworten

1

PROBLEM

  1. Normalerweise, wenn Sie einen DMA-Puffer reservieren oder eine physikalische Adresse erhalten wollen, geschieht dies im Kernel-Bereich, da der Benutzercode niemals mit physischen Adressen herumhacken sollte.
  2. Hugetlbfs stellt nur User-Space-Mappings zur Verfügung, um 1 GB große Seiten zuzuordnen und virtuelle User-Space-Adressen zu erhalten
  3. Es existiert keine Funktion zum Zuordnen einer virtuellen Adresse einer virtuellen rightpage zu einer physischen Adresse

EUREKA

Aber die Funktion existiert! Burried tief im 2.6 Kernel-Quellcode liegt diese Funktion vor, um eine Strukturseite von einer virtuellen Adresse zu erhalten, die als "nur zum Testen" markiert und mit #if 0:

blockiert ist %Vor%

LÖSUNG: Da die obige Funktion nicht tatsächlich in den Kernel kompiliert wird, müssen Sie sie zu Ihrer Treiberquelle hinzufügen.

BENUTZER-SEITEN-WORKFLOW

  1. Ordnen Sie 1gb rigipages beim Booten mit Kernel-Boot-Optionen zu
  2. Rufen Sie get_huge_pages () mit hugetlbfs auf, um den User Space Pointer (virtuelle Adresse)
  3. zu erhalten
  4. Übergeben Sie die virtuelle Benutzeradresse (normaler Pointer an unsigned long) an den Treiber ioctl

KERN-TREIBER-WORKFLOW

  1. Übernehmen Sie die virtuelle Benutzeradresse über ioctl
  2. Rufen Sie follow_huge_addr auf, um die Strukturseite *
  3. zu erhalten
  4. Rufen Sie page_to_phys auf der Strukturseite * auf, um die physische Adresse
  5. zu erhalten
  6. Geben Sie die physische Adresse für das Gerät für DMA
  7. an
  8. Rufen Sie kmap auf der Strukturseite * auf, wenn Sie auch einen virtuellen Kernel-Zeiger
  9. möchten

DISCLAIMER

  • Die obigen Schritte werden einige Jahre später wiederholt. Ich habe den Zugriff auf den ursprünglichen Quellcode verloren. Tu deine Due Diligence und stelle sicher, dass ich keinen Schritt vergesse.
  • Der einzige Grund dafür ist, dass 1 GB große Seiten beim Booten zugewiesen werden und ihre physischen 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 Kernel-Version 2.6.XX verwendet. Es kann einen leichteren Weg geben, dies bei späteren Kernel-Versionen zu tun, oder es kann jetzt völlig unmöglich sein.
muusbolla 26.06.2017, 09:35
quelle
2

Dies wird normalerweise nicht im Kernelraum gemacht, also nicht zu viele Beispiele.

Wie bei jeder anderen Seite werden riesige Seiten mit alloc_pages zur Melodie zugeordnet:

%Vor%

HPAGE_PMD_ORDER ist ein Makro, das die Reihenfolge einer einzelnen großen Seite in Bezug auf normale Seiten definiert. Das bedeutet, dass transparente große Seiten im Kernel aktiviert sind.

Dann können Sie den erhaltenen Seitenzeiger wie gewohnt mit kmap () abbilden.

Disclaimer: Ich habe es nie selbst versucht, also müssen Sie vielleicht etwas experimentieren. 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.

    
oakad 31.10.2013 02:04
quelle

Tags und Links