【技术分享】【原创】linux中vmalloc和相关函数的应用
0赞博客大赛举办的很不错,充分调动了大家的积极性,今天我写写vmalloc和相关函数的作用,可能很多童鞋知道malloc函数,但很少有人知道vmalloc函数,写出来,与大家分享。
vmalloc其实是内存分配函数,它分配虚拟地址空间的连续区域。尽管这段区域在物理上可能是不连续的(要访问其中的每个页面都必须独立地调用函数__get_free_page),内核却认为它们在地址上是连续的。分配的内存空间被映射进入内核数据段中,从用户空间是不可见的-这一点上与其他分配技术不同。vmalloc发生错误时返回0(NULL地址),成功时返回一个指向一个大小为size的线性地址空间的指针。
该函数及其相关函数的原型如下:
void* vmalloc(unsigned long size);
void vfree(void* addr);
void* vremap(unsigned long offset, unsigned long size);
注意在2.1版内核中vremap已经被重命名为ioremap。而且,Linux 2.1引入了一个新的头文件,<linux/vmalloc.h>,使用vmalloc时应将它包含进来。
与其他内存分配函数不同的是,vmalloc返回很“高”的地址值-这些地址要高于物理内存的顶部。由于vmalloc对页表调整后允许用连续的“高”地址访问分配得到的页面,因此处理器是可以访问返回得到的内存区域的。内核能和其他地址一样地使用vmalloc返回的地址,但程序中用到的这个地址与地址总线上的地址并不相同。
用vmalloc分配得到的地址是不能在微处理器之外使用的,因为它们只有在处理器的分页单元之上才有意义。但驱动程序需要真正的物理地址时(象外设用以驱动系统总线的DMA地址),你就不能使用vmalloc了。正确使用vmalloc函数的场合是为软件分配一大块连续的用于缓冲的内存区域。注意vmalloc的开销要比__get_free_pages大,因为它处理获取内存还要建立页表。因此,不值得用vmalloc函数只分配一页的内存空间。
使用vmalloc函数的一个例子函数是create_module系统调用,它利用vmalloc函数来获取被创建模块需要的内存空间。而在insmod调用重定位模块代码后,将会调用memcpy_fromfs函数把模块本身拷贝进分配而得的空间内。
用vmalloc分配得到的内存空间用vfree函数来释放,这就象要用kfree函数来释放kmalloc函数分配得到的内存空间。
和vmalloc一样,vremap(或ioremap)也建立新的页表,但和vmalloc不同的是,vremap实际上并不分配内存。vremap的返回值是个虚拟地址,可以用来访问指定的物理内存区域;得到的这个虚拟地址最后要调用vfree来释放掉。
vremap用于将高内存空间的PCI缓冲区映射到用户空间。例如,如果VGA设备的帧缓冲区被映射到地址0xf0000000(典型的一个值)后,vremap就可以建立正确的页表让处理机可以访问。而系统初始化时建立的页表只是用于访问低于物理地址空间的内存区域。系统的初始化过程并不检测PCI缓冲区,而是由各个驱动程序自己负责管理自己的缓冲区。另外,你不必重映射低于1MB的ISA内存区域,因为这段内存空间可用其他方法访问,
如果你希望驱动程序能在不同的平台间移植,那么使用vremap时就要小心。在一些平台上是不能直接将PCI内存区域映射到处理机的地址空间的,例如Alpha上就不行。此时你就不能象普通内存区域那样地对重映射区域进行访问,你要用readb函数或者其他一些I/O函数(可参见第8章的“1M内存空间之上的ISA内存”一节)。这套函数可以在不同平台间移植。
对vmalloc和vremap函数可分配的内存空间大小并没有什么限制,但为了能检测到程序员的犯下的一些错误,vmalloc不允许分配超过物理内存大小的内存空间。但是记着,vmalloc函数请求过多的内存空间会产生一些和调用kmalloc函数时相同的问题。
vremap和vmalloc函数都是面向页的(它们都会修改页表);因此分配或释放的内存空间实际上都会上调为最近的一个页边界。而且,vremap函数并不考虑如何重映射不是页边界的物理地址。
vmalloc函数的一个小缺点是它不能在中断时间内使用,因为它的内部实现调用了kmalloc(GFP_KERNEL)来获取页表的存储空间。但这不是什么问题-如果__get_free_page函数都还不能满足你的中断处理程序的话,那你还是先修改一下你的软件设计吧。
就写这么多吧,谢谢大家的投票!