Linux kernel 在kmalloced缓冲区上使用延迟io的内核死机

Linux kernel 在kmalloced缓冲区上使用延迟io的内核死机,linux-kernel,linux-device-driver,framebuffer,panic,Linux Kernel,Linux Device Driver,Framebuffer,Panic,我正在为ARM上的SPI LCD显示器编写一个帧缓冲区。在完成之前,我已经编写了一个内存驱动程序,并在Ubuntu(Intel,Virtualbox)下进行了测试。该驱动程序工作正常-我使用kmalloc分配了一块内存,并对其进行了页面对齐(实际上它是页面对齐的),并使用帧缓冲区系统创建了一个/dev/fb1。如果相关的话,我有自己的mmap函数(deferred_io会忽略它,并根据它的外观使用自己的函数) 我已设定: info->screen_base = (u8 __iomem *)

我正在为ARM上的SPI LCD显示器编写一个帧缓冲区。在完成之前,我已经编写了一个内存驱动程序,并在Ubuntu(Intel,Virtualbox)下进行了测试。该驱动程序工作正常-我使用kmalloc分配了一块内存,并对其进行了页面对齐(实际上它是页面对齐的),并使用帧缓冲区系统创建了一个/dev/fb1。如果相关的话,我有自己的mmap函数(deferred_io会忽略它,并根据它的外观使用自己的函数)

我已设定:

info->screen_base = (u8 __iomem *)kmemptr;
info->fix.smem_len = kmem_size;
当我用测试程序打开/dev/fb1并对其进行mmap时,它工作正常。我可以看到x11vnc“共享”fb1的情况:

x11vnc -rawfb map:/dev/fb1@320x240x16  
并使用vnc查看器查看:

gvncviewer strontium:0
我通过写入整个mmapped缓冲区来确保没有溢出,这似乎很好

当我添加延迟io时,问题就出现了。作为测试,我有一个1秒的延迟,被调用的deferred_io函数除了一个pr_devel()打印之外什么也不做。我跟着火车走

现在,测试程序打开/dev/fb1很好,mmap返回ok,但一旦我写入该指针,就会出现内核死机。以下转储实际上来自ARM机器,但在Ubuntu VM上也会出现恐慌:

root@duovero:~/testdrv# ./fbtest1 /dev/fb1
Device opened: /dev/fb3
Screen is: 320 x 240, 16 bpp
Screen size = 153600 bytes
mmap on device succeeded

Unable to handle kernel paging request at virtual address bf81e020
pgd = edbec000
[bf81e020] *pgd=00000000
Internal error: Oops: 5 [#1] SMP ARM
Modules linked in: hhlcd28a(O) sysimgblt sysfillrect syscopyarea fb_sys_fops bnep ipv6 mwifiex_sdio mwifiex btmrvl_sdio firmware_class btmrvl cfg80211 bluetooth rfkill
CPU: 0    Tainted: G           O  (3.6.0-hh04 #1)
PC is at fb_deferred_io_fault+0x34/0xb0
LR is at fb_deferred_io_fault+0x2c/0xb0
pc : [<c0271b7c>]    lr : [<c0271b74>]    psr: a0000113
sp : edbdfdb8  ip : 00000000  fp : edbeedb8
r10: edbeedb8  r9 : 00000029  r8 : edbeedb8
r7 : 00000029  r6 : bf81e020  r5 : eda99128  r4 : edbdfdd8
r3 : c081e000  r2 : f0000000  r1 : 00001000  r0 : bf81e020
Flags: NzCv  IRQs on  FIQs on  Mode SVC_32  ISA ARM  Segment user
Control: 10c5387d  Table: adbec04a  DAC: 00000015
Process fbtest1 (pid: 485, stack limit = 0xedbde2f8)
Stack: (0xedbdfdb8 to 0xedbe0000)
[snipped out hexdump]
[<c0271b7c>] (fb_deferred_io_fault+0x34/0xb0) from [<c00db0c4>] (__do_fault+0xbc/0x470)
[<c00db0c4>] (__do_fault+0xbc/0x470) from [<c00dde0c>] (handle_pte_fault+0x2c4/0x790)
[<c00dde0c>] (handle_pte_fault+0x2c4/0x790) from [<c00de398>] (handle_mm_fault+0xc0/0xd4)
[<c00de398>] (handle_mm_fault+0xc0/0xd4) from [<c049a038>] (do_page_fault+0x140/0x37c)
[<c049a038>] (do_page_fault+0x140/0x37c) from [<c0008348>] (do_DataAbort+0x34/0x98)
[<c0008348>] (do_DataAbort+0x34/0x98) from [<c0498af4>] (__dabt_usr+0x34/0x40)
Exception stack(0xedbdffb0 to 0xedbdfff8)
ffa0:                                     00000280 0000ffff b6f5c900 00000000
ffc0: 00000003 00000000 00025800 b6f5c900 bea6dc1c 00011048 00000032 b6f5b000
ffe0: 00006450 bea6db70 00000000 000085d6 40000030 ffffffff
Code: 28bd8070 ebffff37 e2506000 0a00001b (e5963000)
---[ end trace 7e5ca57bebd433f5 ]---
Segmentation fault
root@duovero:~/testdrv#
root@duovero:~/testdrv#/fbtest1/dev/fb1
设备已打开:/dev/fb3
屏幕为:320 x 240,16 bpp
屏幕大小=153600字节
设备上的mmap已成功
无法处理虚拟地址bf81e020处的内核分页请求
pgd=edbec000
[bf81e020]*pgd=00000000
内部错误:Oops:5[#1]SMP ARM
链接模块:hhlcd28a(O)sysimgblt sysfillrect syscopyarea fb_sys_fops bnep ipv6 mwifiex_sdio mwifiex btmrvl_sdio固件_类btmrvl cfg80211蓝牙rfkill
CPU:0受污染:GO(3.6.0-hh04#1)
PC处于fb_延迟_io_故障+0x34/0xb0
LR处于fb_延迟_io_故障+0x2c/0xb0
pc:[]lr:[]psr:a0000113
sp:edbdfdb8 ip:00000000 fp:edbeedb8
r10:edbeedb8 r9:00000029 r8:edbeedb8
r7:00000029 r6:bf81e020 r5:eda99128 r4:edbdfdd8
r3:c081e000 r2:F0000000R1:00001000 r0:bf81e020
标志:SVC_32 ISA ARM段用户模式下FIQ上的NzCv IRQ
控件:10c5387d表:adbec04a DAC:00000015
过程fbtest1(pid:485,堆栈限制=0xedbde2f8)
堆栈:(0xedbdfdb8到0xedbe0000)
[剪下的碎片]
[](fb_延迟_io_故障+0x34/0xb0)自[](_do_故障+0xbc/0x470)
[](句柄故障+0x2c4/0x790)
[](手柄故障+0x2c4/0x790)来自[](手柄故障+0xc0/0xd4)
[](处理错误+0xc0/0xd4)从[](执行页面错误+0x140/0x37c)
[](do_页面错误+0x140/0x37c)来自[](do_数据中止+0x34/0x98)
[](数据中止+0x34/0x98)从[](数据中止+0x34/0x40)
异常堆栈(0xedbdffb0到0xedbdfff8)
ffa0:00000280 0000ffff b6f5c900 00000000
ffc0:00000003 00000000 00025800 b6f5c900 bea6dc1c 00011048 00000032 b6f5b000
ffe0:00006450 bea6db70 00000000 000085d6 40000030 FFFFFF
代码:28bd8070 ebffff37 e2506000 0a00001b(e5963000)
---[结束记录道7e5ca57bebd433f5]---
分段故障
root@duovero:~/testdrv#

我完全被难住了——其他司机看起来和我的差不多,但我认为他们能工作。实际上大多数人都使用vmalloc-在这方面kmalloc和vmalloc有区别吗?

确认了修复方法,因此我将回答自己的问题:

延迟io将信息mmap更改为自己的,该信息mmap为写入视频内存页设置错误处理程序。在故障处理程序中

  • 根据info->fix.smem\u len检查边界,因此必须设置该边界
  • 获取写入的页面
对于后一种情况,它对待vmalloc的方式与对待kmalloc的方式不同(通过检查info->screen_base查看它是否被vmalloced)。如果您有vmalloced,它将使用screen_base作为虚拟地址。如果您没有使用vmalloc,它会假定感兴趣的地址是info->fix.smem_start中的物理地址

因此,正确使用延迟io

  • 设置screen\u base(char\u iomem*)并将其指向虚拟地址
  • 将info->fix.smem\u len设置为视频缓冲区大小
  • 如果不使用vmalloc,则必须使用virt_to_phys(vid_buffer)将info->fix.smem_start设置为视频缓冲区的物理地址

已在Ubuntu上确认已修复此问题。

哦,克拉姆斯!我想我看到了什么。延迟的io似乎以不同的方式对待vmalloc-对于KAlloced地址,对is_vmalloc_addr()的调用是否返回not true?如果是这样,该死的东西使用info->fix.smem_start而不是screen base。我可不这么认为!它使用pfn_to_页面,我想这是一个物理地址。这应该被记录下来!这就是问题所在——我敢肯定。打字的动作解决了我的问题!似乎延迟io对待kmalloc和vmalloc的方式不同。我会写一个解决方案,因为其他人会碰到这个问题,我会尝试更新内核文档。我想生活是艰难的。