2013-10-18 13 views
8

Tôi đang cố gắng phân bổ bộ đệm DMA cho khối lượng công việc HPC. Nó đòi hỏi 64GB dung lượng bộ đệm. Ở giữa tính toán, một số dữ liệu được tải xuống thẻ PCIe. Thay vì sao chép dữ liệu vào một loạt các bộ đệm 4MB dinky được đưa ra bởi pci_alloc_consistent, tôi muốn tạo 64 bộ đệm 1GB, được hỗ trợ bởi 1Pb HugePages.Làm cách nào để phân bổ bộ đệm DMA được hỗ trợ bởi HugePages 1GB trong mô-đun hạt nhân Linux?

Một số thông tin nền: phiên bản kernel: CentOS 6.4/2.6.32-358.el6.x86_64 tùy chọn khởi động hạt nhân: hugepagesz = 1g hugepages = 64 default_hugepagesz = 1g

phần liên quan của/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

Tôi có thể gắn kết -t hugetlbfs nodev/mnt/hugepages. CONFIG_HUGETLB_PAGE là đúng. MAP_HUGETLB được định nghĩa.

Tôi đã đọc một số thông tin về cách sử dụng libhugetlbfs để gọi get_huge_pages() trong không gian người dùng, nhưng lý tưởng bộ đệm này sẽ được cấp phát trong không gian hạt nhân. Tôi đã thử gọi do_mmap() với MAP_HUGETLB nhưng nó dường như không thay đổi số lượng hugepages miễn phí, vì vậy tôi không nghĩ rằng nó đã thực sự sao lưu mmap với các trang lớn.

Vì vậy, tôi đoán những gì tôi đang nhận được, có bất kỳ cách nào tôi có thể ánh xạ bộ đệm tới 1GB HugePage trong không gian hạt nhân hay không? Hoặc nếu bất cứ ai biết về bất kỳ cách nào khác tôi có thể nhận được một số lượng (1-64GB) bộ nhớ vật lý liền kề có sẵn như là một bộ đệm hạt nhân?

+0

Câu hỏi thú vị, là mục tiêu của bạn chủ yếu để tránh sao chép giữa hạt nhân và không gian người dùng? – ChuckCottrill

+2

Tất cả các API này đều dành cho không gian người dùng. Hãy xem cách thực hiện hugetlbfs, đặc biệt là 'hugetlbfs_file_mmap'. –

+0

@muusbolla Bạn có thể tìm thấy câu trả lời không? –

Trả lời

1

VẤN ĐỀ

  1. Thông thường nếu bạn muốn phân bổ một bộ đệm DMA, hoặc có được một địa chỉ vật lý, điều này được thực hiện trong không gian hạt nhân, như mã người dùng không bao giờ phải làm việc nhiều với các địa chỉ vật lý.
  2. Hugetlbfs chỉ cung cấp ánh xạ sử dụng không gian để bố trí 1GB trang khổng lồ, và nhận được sử dụng không gian địa chỉ ảo
  3. Không có chức năng tồn tại để ánh xạ một địa chỉ ảo dùng hugepage đến một địa chỉ vật lý

EUREKA

Nhưng chức năng không tồn tại! Buried deep in the 2.6 kernel source code nằm chức năng này để có được một trang struct từ một địa chỉ ảo, đánh dấu là "chỉ để thử nghiệm" và bị chặn với # nếu 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; 
} 

SOLUTION: Kể từ khi chức năng trên là không thực sự biên dịch vào hạt nhân, bạn sẽ cần phải thêm nó vào nguồn trình điều khiển của bạn.

USER SIDE Workflow

  1. Phân bổ hugepages 1gb lúc khởi động với các tùy chọn khởi động kernel
  2. get_huge_pages Gọi() với hugetlbfs để có được con trỏ không gian người dùng (địa chỉ ảo)
  3. dùng
  4. đèo địa chỉ ảo (con trỏ bình thường đúc để unsigned long) để ioctl lái xe

KERNEL DRIVER Workflow

  1. Chấp nhận sử dụng địa chỉ ảo qua ioctl
  2. Gọi follow_huge_addr để có được những trang struct *
  3. page_to_phys Gọi trên trang struct * để có được địa chỉ vật lý
  4. Cung cấp địa chỉ vật lý để thiết bị cho DMA
  5. Gọi kmap trên trang struct * nếu bạn cũng muốn có một hạt nhân con trỏ ảo

sỰ TỪ BỎ

  • Các bước trên được thu hồi vài năm sau đó. Tôi đã mất quyền truy cập vào mã nguồn ban đầu. Làm thẩm định của bạn và chắc chắn rằng tôi không quên một bước.
  • Lý do duy nhất hoạt động này là do 1GB trang lớn được cấp phát lúc khởi động và địa chỉ thực của chúng bị khóa vĩnh viễn. Đừng cố gắng ánh xạ địa chỉ ảo người dùng không được hỗ trợ 1GBhugepage vào địa chỉ vật lý DMA! Bạn sẽ có một thời gian tồi tệ!
  • Kiểm tra cẩn thận trên hệ thống của bạn để xác nhận rằng các trang lớn 1GB của bạn trên thực tế bị khóa trong bộ nhớ vật lý và mọi thứ đang hoạt động chính xác. Mã này hoạt động hoàn hảo trên thiết lập của tôi, nhưng có nguy cơ lớn ở đây nếu có sự cố.
  • Mã này chỉ được đảm bảo hoạt động trên kiến ​​trúc x86/x64 (trong đó địa chỉ vật lý == địa chỉ xe buýt) và phiên bản hạt nhân 2.6.XX. Có thể có một cách dễ dàng hơn để làm điều này trên các phiên bản hạt nhân sau này, hoặc bây giờ hoàn toàn không thể.
2

Điều này thường không được thực hiện trong không gian hạt nhân, vì vậy không quá nhiều ví dụ.

Cũng giống như bất kỳ trang nào khác, các trang lớn được phân bổ với alloc_pages, theo giai điệu:

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

HPAGE_PMD_ORDER là một vĩ mô, xác định một trật tự của một trang lớn duy nhất trong điều kiện của các trang bình thường. Ở trên ngụ ý rằng các trang lớn trong suốt được bật trong hạt nhân.

Sau đó, bạn có thể tiến hành ánh xạ con trỏ trang thu được theo cách thông thường với kmap().

Tuyên bố từ chối trách nhiệm: Tôi chưa bao giờ thử bản thân mình, vì vậy bạn có thể phải thực hiện một số thử nghiệm xung quanh. Một điều cần kiểm tra là: HPAGE_PMD_SHIFT đại diện cho một đơn đặt hàng của một trang "lớn" nhỏ hơn. Nếu bạn muốn sử dụng các trang 1GB khổng lồ này, có thể bạn sẽ cần thử một thứ tự khác, có thể là PUD_SHIFT - PAGE_SHIFT.

+1

Các trang lớn trong suốt có được hỗ trợ cho các trang 1 GB không? – osgx

Các vấn đề liên quan