3

hugepages に裏打ちされたバッファーを使用するドライバーで作業していますが、hugepages の連続性に問題があることがわかりました。

mmapユーザー空間では、プログラムはsyscallを使用して hugepages に裏打ちされた大きなバッファーを割り当てます。バッファーは、呼び出しを介してドライバーに伝達されioctlます。ドライバーはget_user_pages関数を使用して、そのバッファーのメモリ アドレスを取得します。

これは、1 GB (1 hugepage) のバッファー サイズで完全に機能します。get_user_pages多くのページ ( HUGE_PAGE_SIZE / PAGE_SIZE) が返されますが、それらはすべて連続しているため、問題はありません。最初のページのアドレスを取得して、それを操作page_addressします。remap_pfn_rangeドライバーは、別のプログラムがmmapchar デバイスで呼び出しを行うときに、そのバッファーをユーザー空間にマップすることもできます。

ただし、バッファが複数の hugepage に支えられている場合、事態は複雑になります。カーネルは、非シーケンシャルな hugepage に裏打ちされたバッファーを返すことができるようです。つまり、hugepage プールのレイアウトがこのようなものである場合

+------+------+------+------+
| HP 1 | HP 2 | HP 3 | HP 4 |
+------+------+------+------+

HP1 と HP4、または HP3 と HP2 を予約することで、hugepage でバックアップされたバッファーの要求を満たすことができます。つまりget_user_pages、最後のケースでページを取得すると、ページ 0 のアドレスは実際にはページ 262.144 (次の hugepage の先頭) のアドレスの 1 GB 後になります。

これらのページへのアクセスを順次処理する方法はありますか? バッファ全体を使用できるように、アドレスを並べ替えて下位のアドレスを見つけようとしました(たとえば、カーネルが HP3、HP2 に基づくバッファを提供する場合、HP2 のアドレスをベース アドレスとして使用します)が、データがスクランブルされるようです。ユーザー空間(その並べ替えられたバッファーのオフセット0は、ユーザー空間バッファーのオフセット1GBの可能性があります)。

TL;DR: 順序付けられていないヒュージページが 1 つ以上ある場合、Linux カーネル ドライバーで順番にアクセスする方法はありますか?

ところで、私は 3.8.0-29-generic カーネルを搭載した Linux マシンで作業しています。

4

1 に答える 1

5

CL によって提案された関数を使用して、vm_map_ramマップされたヒュージページの数に関係なく、メモリを順次アクセスできるようにメモリを再マップすることができました。誰かに役立つ場合に備えて、ここにコードを残します (エラー制御は含まれていません)。

struct page** pages;
int retval;
unsigned long npages;
unsigned long buffer_start = (unsigned long) huge->addr; // Address from user-space map.
void* remapped;

npages =  1 + ((bufsize- 1) / PAGE_SIZE); 

pages = vmalloc(npages * sizeof(struct page *));

down_read(&current->mm->mmap_sem);
retval = get_user_pages(current, current->mm, buffer_start, npages,
                     1 /* Write enable */, 0 /* Force */, pages, NULL);
up_read(&current->mm->mmap_sem);    

nid = page_to_nid(pages[0]); // Remap on the same NUMA node.

remapped = vm_map_ram(pages, npages, nid, PAGE_KERNEL);

// Do work on remapped.
于 2014-07-31T12:34:31.823 に答える