curious
curious

Reputation: 85

Allocating large amount of memory to Kernel Module using vmalloc

I am trying to allocate a large memory to kernel module using vmalloc(). I am unable to allocate more than 2GB of memory on a 64-bit Linux (3.10.0-514.2.2.el7.x86_64) with 64GB ram.

These are the relevant code parts:

...

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);
   ...

Is there a limitation to the size of memory that can be allocated via vmalloc? Is there another way to allocate a large amount of memory to a kernel module?

Upvotes: 2

Views: 2031

Answers (2)

Ctx
Ctx

Reputation: 18410

You refer to the code here: Simple Block Driver in the comments, which is essential to see to answer your question.

The reason is, that you are trying to allocate 16 Exabytes of data. This calculation in sbd_init() is the reason:

Device.size = nsectors * logical_block_size;

Device.size is unsigned long while the module parameters nsectors and logical_block_size are integers.

Now, when you set locgical_block_size to 1024 and nsectors to 2097152 (which totals to 2GB of space), the calculation is done as signed integer, thus the result is:

1024 * 2097152 = -2147483648

When this is casted implicitly to unsigned long (by the assignment to Device.size), the result is 18446744071562067968, which is then passed to vmalloc(), (probably) slightly exceeding the physical memory and the vmalloc reserved area, which is 32TB on linux x86_64.

The solution is to perform the calculation as unsigned long:

Device.size = (unsigned long) nsectors * logical_block_size;

Then it should work as expected.

Upvotes: 2

syntagma
syntagma

Reputation: 24344

In older versions of Linux kernel there was a 64 MB limit on memory that vmalloc() can allocate but in version 3.10.* it should theoretically be limited by the physical memory.

Upvotes: 0

Related Questions