我有一个驱动程序将 DMA 传输到在用户空间应用程序中分配的内存,然后传递给内核(get_user_pages ...)。
问题:调用 free() 时收到“无效指针”消息。我打印两个指针值,它们是相等的,没有改变。当我使用 posix_memalign() 而不是 malloc() 时,该错误不会发生。在 posix_memalign() 的情况下,我总是得到页面对齐的指针(0x....000)。使用 malloc() 它通常是未对齐的地址。
我已经尝试完全跳过驱动程序 DMA 传输调用,基本上只是在应用程序中执行 malloc() 和 free() - 然后它总是有效!
这告诉我,内核似乎以某种方式认为页面仍然在内核空间中“锁定”左右。
我已经挖掘了一些驱动程序,特别是驱动程序/媒体/pci/ivtv/ivtv-udma.c 和 ivtv-yuv.c 看起来很有趣,因为它们看起来完全一样。
在那里我找到了我已经在我的驱动程序中尝试过的函数“put_page”,但它没有帮助,而且驱动程序然后卡住了。
有人可以指出我正确的方向或信息来源,如何正确处理内核空间中的此类用户页面?
这里是相关代码。顺序基本上是:get_user_pages -> dma_map_page -> kick off HW DMA (in our FPGA) -> dma_unmap_page -> SetPageDirty -> put_page
但是对于未对齐的地址,仍然会发生与以下相同的错误。
perform_user_dma_func(..)
{
[...]
rv = get_user_pages( current, current->mm, uaddr, nr_pages, (direction == DMA_FROM_DEVICE), 0, pages, NULL);
if( rv < nr_pages )
goto CLEANUP;
/*--- build scatter/gather list ---*/
offset = uaddr & ~PAGE_MASK;
#ifdef VME4L_DBG_DMA_DATA
initOffs = offset;
#endif
for ( i = 0; i < nr_pages; ++i, sgList++ ) {
struct page *page = pages[i];
sgList->dmaLength = PAGE_SIZE - offset;
dmaAddr = dma_map_page( pDev, page, 0x0, PAGE_SIZE, direction );
if ( dma_mapping_error( pDev, dmaAddr ) ) {
printk( KERN_ERR "error mapping DMA space with dma_map_page\n" );
goto CLEANUP;
} else {
sgList->dmaDataAddress = dmaAddr + offset; /* Add offset between page begin and payload data, often > 0 */
sgList->dmaPageAddress = dmaAddr; /* store page address for later dma_unmap_page */
}
if( totlen + sgList->dmaLength > count )
sgList->dmaLength = count - totlen;
VME4LDBG(" sglist %d: pageAddr=%p off=0x%lx dmaAddr=%p length=0x%x\n", i, page_address(page), offset, dmaAddr, sgList->dmaLength);
totlen += sgList->dmaLength;
offset = 0;
}
/*--- now do DMA in HW (device touches memory) ---*/
rv = vme4l_perform_zc_dma( spc, sgListStart, nr_pages, blk->direction, blk->vmeAddr, swapMode );
CLEANUP:
/*--- free pages ---*/
sgList = sgListStart;
for (i = 0; i < nr_pages; i++, sgList++) {
dma_unmap_page( pDev, sgList->dmaPageAddress, PAGE_SIZE, direction );
}
/* mark pages as dirty */
if( blk->direction == READ ) {
for (i = 0; i < nr_pages; i++ ) {
if ( !PageReserved( pages[i] ))
SetPageDirty( pages[i] );
}
}
sgList = sgListStart;
for (i = 0; i < nr_pages; i++, sgList++) {
/* __free_page( pages[i] ); */
put_page( pages[i] );
}
[...]
}
usimg malloc 缓冲区(未对齐内存)时的错误消息:
*** Error in `vme4l_rwex': free(): invalid pointer: 0x00000000008e4010 ***
======= Backtrace: =========
/lib/x86_64-linux-gnu/libc.so.6(+0x777e5)[0x7fe0a34367e5]
/lib/x86_64-linux-gnu/libc.so.6(+0x8037a)[0x7fe0a343f37a]
/lib/x86_64-linux-gnu/libc.so.6(cfree+0x4c)[0x7fe0a344353c]
vme4l_rwex[0x4010f8]
/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf0)[0x7fe0a33df830]
vme4l_rwex[0x401419]
======= Memory map: ========
00400000-00402000 r-xp 00000000 08:15 931122 /usr/local/bin/vme4l_rwex
00601000-00602000 r--p 00001000 08:15 931122 /usr/local/bin/vme4l_rwex
00602000-00603000 rw-p 00002000 08:15 931122 /usr/local/bin/vme4l_rwex
008e4000-00906000 rw-p 00000000 00:00 0 [heap]
7fe09c000000-7fe09c021000 rw-p 00000000 00:00 0
7fe09c021000-7fe0a0000000 ---p 00000000 00:00 0
7fe0a31a9000-7fe0a31bf000 r-xp 00000000 08:15 1035123 /lib/x86_64-linux-gnu/libgcc_s.so.1
7fe0a31bf000-7fe0a33be000 ---p 00016000 08:15 1035123 /lib/x86_64-linux-gnu/libgcc_s.so.1
7fe0a33be000-7fe0a33bf000 rw-p 00015000 08:15 1035123 /lib/x86_64-linux-gnu/libgcc_s.so.1
7fe0a33bf000-7fe0a357f000 r-xp 00000000 08:15 1045483 /lib/x86_64-linux-gnu/libc-2.23.so
7fe0a357f000-7fe0a377f000 ---p 001c0000 08:15 1045483 /lib/x86_64-linux-gnu/libc-2.23.so
7fe0a377f000-7fe0a3783000 r--p 001c0000 08:15 1045483 /lib/x86_64-linux-gnu/libc-2.23.so
7fe0a3783000-7fe0a3785000 rw-p 001c4000 08:15 1045483 /lib/x86_64-linux-gnu/libc-2.23.so
7fe0a3785000-7fe0a3789000 rw-p 00000000 00:00 0
7fe0a3789000-7fe0a378b000 r-xp 00000000 08:15 905612 /usr/local/lib/libusr_utl.so
7fe0a378b000-7fe0a398a000 ---p 00002000 08:15 905612 /usr/local/lib/libusr_utl.so
7fe0a398a000-7fe0a398b000 r--p 00001000 08:15 905612 /usr/local/lib/libusr_utl.so
7fe0a398b000-7fe0a398c000 rw-p 00002000 08:15 905612 /usr/local/lib/libusr_utl.so
7fe0a398c000-7fe0a398e000 r-xp 00000000 08:15 905739 /usr/local/lib/libvme4l_api.so
7fe0a398e000-7fe0a3b8e000 ---p 00002000 08:15 905739 /usr/local/lib/libvme4l_api.so
7fe0a3b8e000-7fe0a3b8f000 r--p 00002000 08:15 905739 /usr/local/lib/libvme4l_api.so
7fe0a3b8f000-7fe0a3b90000 rw-p 00003000 08:15 905739 /usr/local/lib/libvme4l_api.so
7fe0a3b90000-7fe0a3bb6000 r-xp 00000000 08:15 1045455 /lib/x86_64-linux-gnu/ld-2.23.so
7fe0a3da6000-7fe0a3da9000 rw-p 00000000 00:00 0
7fe0a3db2000-7fe0a3db5000 rw-p 00000000 00:00 0
7fe0a3db5000-7fe0a3db6000 r--p 00025000 08:15 1045455 /lib/x86_64-linux-gnu/ld-2.23.so
7fe0a3db6000-7fe0a3db7000 rw-p 00026000 08:15 1045455 /lib/x86_64-linux-gnu/ld-2.23.so
7fe0a3db7000-7fe0a3db8000 rw-p 00000000 00:00 0
7ffd66125000-7ffd66146000 rw-p 00000000 00:00 0 [stack]
7ffd661b4000-7ffd661b6000 r--p 00000000 00:00 0 [vvar]
7ffd661b6000-7ffd661b8000 r-xp 00000000 00:00 0 [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall]
Aborted