Reputation: 85
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
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
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