Allocating a lot of memory for a kernel module using vmalloc
I am trying to allocate more memory for a kernel module using vmalloc()
. I cannot allocate more than 2GB of memory on 64-bit Linux (3.10.0-514.2.2.el7.x86_64) with 64GB of RAM.
These are the relevant parts of the code:
...
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 limit to the amount of memory that can be allocated through vmalloc
? Is there another way to allocate a large amount of memory for the kernel module?
source to share
You reference the code here: Simple Block Driver in the comments, which is important to answer your question.
The reason is that you are trying to allocate 16 Exabytes of data. This calculation sbd_init()
is the reason:
Device.size = nsectors * logical_block_size;
Device.size 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 is up to 2GB of space) the computation is done as a signed integer, thus the result is:
1024 * 2097152 = -2147483648
If this is implicitly pointed to unsigned long
(by assigning Device.size) the result will be 18446744071562067968
, which is then passed to vmalloc()
(possibly) slightly larger physical memory, and vmalloc is an area reserved which is 32TB on Linux x86_64.
The solution is to do the calculation like unsigned long
:
Device.size = (unsigned long) nsectors * logical_block_size;
Then it should work as expected.
source to share