kmalloc()kcalloc()vmalloc()和kzalloc()之间有什么区别?

时间:2011-03-01 10:22:10

标签: linux linux-kernel malloc driver

Hi all, 

我正在调试设备驱动程序,而且我遇到内核恐慌。检查回溯或错误日志后,似乎问题出在kmalloc上。我想也许我可以用其他分配函数改变kmalloc。他们有什么不同?

这是错误日志:

Unable to handle kernel NULL pointer dereference at virtual address 0000000d
pgd = c7bdc000
[0000000d] *pgd=4785f031, *pte=00000000, *ppte=00000000
Internal error: Oops: 17 [#1] PREEMPT
Modules linked in: bcm5892_secdom_fw(P) bcm5892_lcd snd_bcm5892 msr bcm5892_sci     bcm589x_ohci_p12 bcm5892_skeypad hx_decoder(P) pinnacle hx_memalloc(P) bcm_udc_dwc         scsi_mod g_serial sd_mod usb_storage
CPU: 0    Tainted: P           (2.6.27.39-WR3.0.2ax_standard #1)
PC is at __kmalloc+0x70/0xdc
LR is at __kmalloc+0x48/0xdc
pc : [<c0098cc8>]    lr : [<c0098ca0>]    psr: 20000093
sp : c7a9fd50  ip : c03a4378  fp : c7a9fd7c
r10: bf0708b4  r9 : c7a9e000  r8 : 00000040
r7 : bf06d03c  r6 : 00000020  r5 : a0000093  r4 : 0000000d
r3 : 00000000  r2 : 00000094  r1 : 00000020  r0 : c03a4378
Flags: nzCv  IRQs off  FIQs on  Mode SVC_32  ISA ARM  Segment user
Control: 00c5387d  Table: 47bdc008  DAC: 00000015
Process sh (pid: 1088, stack limit = 0xc7a9e260)
Stack: (0xc7a9fd50 to 0xc7aa0000)
fd40:                                     c7a6a1d0 00000020 c7a9fd7c c7ba8fc0
fd60: 00000040 c7a6a1d0 00000020 c71598c0 c7a9fd9c c7a9fd80 bf06d03c c0098c64
fd80: c71598c0 00000003 c7a6a1d0 bf06c83c c7a9fdbc c7a9fda0 bf06d098 bf06d008
fda0: c7159880 00000000 c7a6a2d8 c7159898 c7a9fde4 c7a9fdc0 bf06d130 bf06d078
fdc0: c79ca000 c7159880 00000000 00000000 c7afbc00 c7a9e000 c7a9fe0c c7a9fde8
fde0: bf06d4b4 bf06d0f0 00000000 c79fd280 00000000 0f700000 c7a9e000 00000241
fe00: c7a9fe3c c7a9fe10 c01c37b4 bf06d300 00000000 c7afbc00 00000000 00000000
fe20: c79cba84 c7463c78 c79fd280 c7473b00 c7a9fe6c c7a9fe40 c00a184c c01c35e4
fe40: 00000000 c7bb0005 c7a9fe64 c79fd280 c7463c78 00000000 c00a1640 c785e380
fe60: c7a9fe94 c7a9fe70 c009c438 c00a164c c79fd280 c7a9fed8 c7a9fed8 00000003
fe80: 00000242 00000000 c7a9feb4 c7a9fe98 c009c614 c009c2a4 00000000 c7a9fed8
fea0: c7a9fed8 00000000 c7a9ff64 c7a9feb8 c00aa6bc c009c5e8 00000242 000001b6
fec0: 000001b6 00000241 00000022 00000000 00000000 c7a9fee0 c785e380 c7473b00
fee0: d8666b0d 00000006 c7bb0005 00000300 00000000 00000000 00000001 40002000
ff00: c7a9ff70 c79b10a0 c79b10a0 00005402 00000003 c78d69c0 ffffff9c 00000242
ff20: 000001b6 c79fd280 c7a9ff64 c7a9ff38 c785e380 c7473b00 00000000 00000241
ff40: 000001b6 ffffff9c 00000003 c7bb0000 c7a9e000 00000000 c7a9ff94 c7a9ff68
ff60: c009c128 c00aa380 4d18b5f0 08000000 00000000 00071214 0007128c 00071214
ff80: 00000005 c0027ee4 c7a9ffa4 c7a9ff98 c009c274 c009c0d8 00000000 c7a9ffa8
ffa0: c0027d40 c009c25c 00071214 0007128c 0007128c 00000241 000001b6 00000000
ffc0: 00071214 0007128c 00071214 00000005 00073580 00000003 000713e0 400010d0
ffe0: 00000001 bef0c7b8 000269cc 4d214fec 60000010 0007128c 00000000 00000000


Backtrace:

[<c0098c58>] (__kmalloc+0x0/0xdc) from [<bf010a00>] (GadgetEpRequestAlloc+0x28/0x70 [bcm_udc_dwc])

 r8:bf017c80 r7:c79de2d8 r6:c79de2d8 r5:00000000 r4:00000040

[<bf0109d8>] (GadgetEpRequestAlloc+0x0/0x70 [bcm_udc_dwc]) from [<bf0181d4>] (gs_alloc_req+0x44/0xf0 [g_serial])

 r5:00000000 r4:00000040

[<bf018190>] (gs_alloc_req+0x0/0xf0 [g_serial]) from [<bf0182b4>]     (gs_alloc_requests+0x34/0xb4 [g_serial])

 r7:c79de2d8 r6:c79aa198 r5:00000000 r4:c79aa180

[<bf018280>] (gs_alloc_requests+0x0/0xb4 [g_serial]) from [<bf018368>] (gs_start_io+0x34/0xb8 [g_serial])

 r9:c7b84000 r8:c7b48c00 r7:c79aa198 r6:c79de2d8 r5:c79aa180
r4:c79aa180

[<bf018334>] (gs_start_io+0x0/0xb8 [g_serial]) from [<bf018730>] (gs_open+0x1d0/0x23c [g_serial])

 r9:c7b84000 r8:c7b48c00 r7:00000000 r6:00000000 r5:c79aa180
r4:c7924300

[<bf018560>] (gs_open+0x0/0x23c [g_serial]) from [<c01c3754>] (tty_open+0x1dc/0x314)

[<c01c3578>] (tty_open+0x0/0x314) from [<c00a184c>] (chrdev_open+0x20c/0x22c)

[<c00a1640>] (chrdev_open+0x0/0x22c) from [<c009c438>] (__dentry_open+0x1a0/0x2b8)

 r8:c79aa300 r7:c00a1640 r6:00000000 r5:c74685a8 r4:c7a9f5a0

[<c009c298>] (__dentry_open+0x0/0x2b8) from [<c009c614>] (nameidata_to_filp+0x38/0x50)

[<c009c5dc>] (nameidata_to_filp+0x0/0x50) from [<c00aa6bc>] (do_filp_open+0x348/0x6f4)

 r4:00000000

[<c00aa374>] (do_filp_open+0x0/0x6f4) from [<c009c128>] (do_sys_open+0x5c/0x170)

[<c009c0cc>] (do_sys_open+0x0/0x170) from [<c009c274>] (sys_open+0x24/0x28)

 r8:c0027ee4 r7:00000005 r6:0007121c r5:0007129c r4:0007121c

[<c009c250>] (sys_open+0x0/0x28) from [<c0027d40>] (ret_fast_syscall+0x0/0x2c)
Code: e59c4080 e59c8090 e3540000 159c308c (17943103)

---[ end trace b9a765ee07f8c06b ]---

3 个答案:

答案 0 :(得分:17)

kmalloc不太可能被破坏,因为它在内核中的任何地方都被使用。但是,kmalloc可能会失败。假设kmalloc没有被破坏,那么代码调用是一个很好的候选者:

  • kmalloc周围的代码如何?也许你可以向我们展示这一部分。
  • 回溯之前的部分是什么?它可以包含有价值的信息。

更直接地回答问题:

  • kzalloc在返回指针之前将内存归零
  • kcmalloc为数组分配内存,它不是kmalloc的替代品:

    void * kcalloc(size_t n,size_t size,gfp_t flags)

  • vmalloc与kmalloc相同,只是它分配的内存几乎是连续的。底层的物理内存可能是不连续的。

所以kmalloc最终可以通过调用kzalloc来取代,但它不太可能解决你的问题。

答案 1 :(得分:5)

我认为kmalloc,vmalloc和其他分配技术之间的选择在于实现。他们每个人的失败也是偶然的。 如果你需要多页内存而不是页面分配技术。它们既简单又快捷。 但是,如果您需要一定数量的数据(以字节表示),则选择保留在kmalloc(及其变体)和vmalloc之间。 kmalloc速度更快,并提供连续的内存分配(在DMA的情况下尤其有用)。实现它的算法非常快。但是,如果您的内存高度碎片化,那么当您请求大内存时可能会出现问题。如果它找不到足够的连续空间,即使内存有足够的空间容纳也会失败。 另一方面,vmalloc不需要连续的内存分配。但是,它很慢。它适用于设置页表条目。此外,内核通常不会为vmalloc分配大量空间。

因此,在您的情况下,我认为这取决于您使用的应用程序类型。但是,在大多数情况下使用vmalloc而不是kmalloc不是解决方案(高度分段内存中的大内存分配除外)。在这种情况下,您可以直接选择页面分配。

答案 2 :(得分:2)

kmalloc只有当你的内存碎片化时才会成为罪魁祸首,如果没有找到连续的内存则无法分配内存。因此,取决于您尝试分配的内存大小。

在这种情况下,使用vmalloc会产生良好的效果。在最佳实践中,

  1. 如果你想使用kmalloc更好地使用kzmalloc。

  2. 如果您的分配更好,请使用vmalloc。

  3. 现在根据错误情况检查最适合您的方法。