当前位置: 首页 > >

内核空间到用户空间的共享内存映射

发布时间:



当内核空间和用户空间存在大量数据交互时, 共享内存映射就成了这种情况下的不二选择; 它能够最大限度的降低内核空间和用户空间之间的数据拷贝, 从而大大提高系统的性能.




以下是创建从内核空间到用户空间的共享内存映射的模板代码(在内核2.6.18和2.6.32上测试通过):


1.内核空间分配内存:


#include
#include
#include

int mmap_alloc(int require_buf_size)
{
? struct page *page;
?
? mmap_size = PAGE_ALIGN(require_buf_size);

#if USE_KMALLOC //for kmalloc
? mmap_buf = kzalloc(mmap_size, GFP_KERNEL);
? if (!mmap_buf) {
??? return -1;
? }
? for (page = virt_to_page(mmap_buf ); page < virt_to_page(mmap_buf + mmap_size); page++) {
??? SetPageReserved(page);
? }
#else //for vmalloc
? mmap_buf? = vmalloc(mmap_size);
? if (!mmap_buf ) {
??? return -1;
? }
? for (i = 0; i < mmap_size; i += PAGE_SIZE) {
??? SetPageReserved(vmalloc_to_page((void *)(((unsigned long)mmap_buf) + i)));
? }
#endif

? return 0;
}



2.用户空间映射内存


int test_mmap()
{
? mmap_fd = open("/dev/mmap_dev", O_RDWR);
? mmap_ptr = mmap(NULL, mmap_size, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_LOCKED, mmap_fd, 0);
? if (mmap_ptr == MAP_FAILED) {
??? return -1;
? }
? return 0;
}




3.内核空间映射内存: 实现file_operations的mmap函数
static int mmap_mmap(struct file *filp, struct vm_area_struct *vma)
{
? int ret;
? unsigned long pfn;
? unsigned long start = vma->vm_start;
? unsigned long size = PAGE_ALIGN(vma->vm_end - vma->vm_start);

? if (size > mmap_size || !mmap_buf) {
??? return -EINVAL;
? }

#if USE_KMALLOC
? return remap_pfn_range(vma, start, (virt_to_phys(mmap_buf) >> PAGE_SHIFT), size, PAGE_SHARED);
#else
? /* loop over all pages, map it page individually */
? while (size > 0) {
????????? pfn = vmalloc_to_pfn(mmap_buf);
????????? if ((ret = remap_pfn_range(vma, start, pfn, PAGE_SIZE, PAGE_SHARED)) < 0) {
??????????? return ret;
????????? }
????????? start += PAGE_SIZE;
????????? mmap_buf += PAGE_SIZE;
????????? size -= PAGE_SIZE;
? }
#endif
? return 0;
}

static const struct file_operations mmap_fops = {
? .owner = THIS_MODULE,
? .ioctl = mmap_ioctl,
? .open = mmap_open,
? .mmap = mmap_mmap,
? .release = mmap_release,
};



4.用户空间撤销内存映射


void test_munmap()
{?? ?
? munmap(mmap_ptr, mmap_size);
? close(mmap_fd);
}



5.内核空间释放内存; 必须在用户空间执行munmap系统调用后才能释放

void mmap_free()
{
#if USE_KMALLOC
? struct page *page;
? for (page = virt_to_page(mmap_buf); page < virt_to_page(mmap_buf + mmap_size); page++) {
??? ClearPageReserved(page);
? }
? kfree(mmap_buf);
#else
? int i;
? for (i = 0; i < mmap_size; i += PAGE_SIZE) {
??? ClearPageReserved(vmalloc_to_page((void *)(((unsigned long)mmap_buf) + i)));
? }
? vfree(mmap_buf);
#endif
? mmap_buf = NULL;
}




参考资料:


http://www.scs.ch/~frey/linux/memorymap.html








友情链接: