使用vmalloc为内核模块分配大量内存

时间:2017-05-30 10:29:28

标签: c linux-kernel kernel-module

我正在尝试使用vmalloc()为内核模块分配一个大内存。 我无法在具有64GB RAM的64位Linux(3.10.0-514.2.2.el7.x86_64)上分配超过2GB的内存。

以下是相关的代码部分:

...

static int logical_block_size = 512;
module_param(logical_block_size, int, 0);
static int nsectors = 1024; /* How big the drive is */
module_param(nsectors, int, 0);

...

/*
 * The internal representation of our device.
*/
static struct sbd_device {
    unsigned long size;
    spinlock_t lock;
    u8 *data;
    struct gendisk *gd;
} Device;

...

static int __init sbd_init(void) {
    /*
     * Set up our internal device.
     */
   Device.size = nsectors * logical_block_size;
   spin_lock_init(&Device.lock);
   Device.data = vmalloc(Device.size);
   ...

可以通过vmalloc分配的内存大小是否有限制?是否有另一种方法可以为内核模块分配大量内存?

2 个答案:

答案 0 :(得分:0)

在早期版本的Linux内核中,vmalloc()可以分配的内存限制为64 MB,但在版本3.10.*中,它理论上应该受到物理内存的限制。

答案 1 :(得分:0)

您可以在评论中引用此处的代码:Simple Block Driver,这对于回答您的问题至关重要。

原因是,您尝试分配 16 Exabytes 数据。 sbd_init()中的此计算是原因:

Device.size = nsectors * logical_block_size;

Device.size为unsigned long,而模块参数nsectorslogical_block_size为整数。

现在,当您将locgical_block_size设置为1024并将nsectors设置为2097152(总计为2GB的空间)时,计算将以有符号整数完成,因此结果是:

1024 * 2097152 = -2147483648

当隐式地将其转换为unsigned long时(通过赋值给Device.size),结果为18446744071562067968,然后传递给vmalloc(),(可能)稍微超过物理内存和vmalloc保留区域,在linux x86_64上为32TB。

解决方案是以unsigned long

执行计算
Device.size = (unsigned long) nsectors * logical_block_size;

然后它应该按预期工作。