URN Logo
UNIX Resources » Linux » China Linux Forum » Linux内核技术 » 18 » nopage多页映射出错,请教!
announcement 声明: 本页内容为中国Linux论坛的内容镜像,文章的版权以及其他所有的相关权利属于中国Linux论坛和相应文章的作者,如果转载,请注明文章来源及相关版权信息。
Resources
China Linux Forum(finished)
Linux Forum(finished)
FreeBSD China(finished)
linuxforum.net
  业界新闻与评论
  自由软件杂谈
  IT 人生
  Linux软件快递
  翻译作坊
  Linux图书与评论
  GNU Emacs/XEmacs
  Linux 中文环境和中文化
  Linux桌面与办公软件
  Linux 多媒体与娱乐版
  自由之窗Mozilla
  笔记本电脑上的Linux
  Gentoo
  Debian 一族
  网络管理技术
  Linux 安装与入门
  WEB服务器和FTP服务器
  域名服务器和邮件服务器
  Linux防火墙和代理服务器应用
  文件及打印服务器
  技术培训与认证
  TI专版
  Linux内核技术
  Linux 嵌入技术
  Linux设备驱动程序
  Linux 集群技术
  LINUX平台数据库
  系统和网络安全
  CPU 与 编译器
  系统计算研究所专栏
  Linux下的GUI软件开发
  C/C++编程版
  PHP 技 术
  Java&jsp技术
  Shell编程技术
  Perl 编 程
  Python 编 程
  XML/Web Service 技术
  永远的Unix
  FreeBSD世界
   
nopage多页映射出错,请教!
nopage多页映射出错,请教! - ywfscu [2007-11-23 20:15 | 7,599 byte(s)]
 
Re: nopage多页映射出错,请教! - wheelz [2007-11-25 01:14 | 456 byte(s)]
 
Re: nopage多页映射出错,请教! - ywfscu [2007-11-25 19:53 | 481 byte(s)]
 
Re: nopage多页映射出错,请教! - wheelz [2007-11-25 20:29 | 480 byte(s)]
 
Subject: nopage多页映射出错,请教!
Author: ywfscu    Posted: 2007-11-23 20:15    Length: 7,599 byte(s)
[Original] [Print] [Top]
我在内核模块中用__get_free_pages分配了3页空间,然后在nopage中一页一页映射。结果测试程序第一次运行正常,第二次运行,系统死掉。模块代码和测试代码如下:
//module
#include <linux/config.h>
#include <linux/module.h>
#include <linux/version.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/types.h>

#include <linux/pci.h>
#include <linux/device.h>
#include <linux/cdev.h>


#include <linux/slab.h>
#include <linux/gfp.h>
#include <linux/sched.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/kdev_t.h>

dev_t devID ;
struct cdev test_cdev ;
struct class_simple* test_class;
unsigned char* mem_pool ;
unsigned int mem_pool_size ;

struct page* test_vma_nopage(struct vm_area_struct* vma, unsigned long address, int* type)
{
struct page* page;
unsigned long offset;
void* pageptr ;

pageptr=NULL ;
page=NOPAGE_SIGBUS;
offset=address-vma->vm_start+(vma->vm_pgoff << PAGE_SHIFT) ;


printk(" start:0x%p, end:0x%p, addr:0x%p, vm_pgoff:%lu, offset:%lu",
(void*)vma->vm_start, (void*)vma->vm_end, (void*)address, vma->vm_pgoff, offset);

if(offset > mem_pool_size)
goto out ;

pageptr = mem_pool + offset ;
page = virt_to_page(pageptr) ;

get_page(page) ;

if(type)
*type = VM_FAULT_MINOR ;


out:
return page ;
}

void test_vma_open(struct vm_area_struct *vma)
{
}
void test_vma_close(struct vm_area_struct *vma)
{
}
struct vm_operations_struct test_vm_ops =
{
.open = test_vma_open,
.nopage = test_vma_nopage,
.close = test_vma_close,
};

int test_mmap(struct file *filp, struct vm_area_struct *vma)
{
printk(" mmap:start:0x%p, end:0x%p",(void*) vma->vm_start, (void*)vma->vm_end);

vma->vm_flags |= VM_RESERVED ;
vma->vm_ops=&test_vm_ops;

test_vma_open(vma);

return 0;
}

struct file_operations test_fops =
{
.owner = THIS_MODULE,
.mmap = test_mmap,
};



static int __init initialization_test(void)
{
int ret ;

ret=alloc_chrdev_region(&devID,0,1,"mmap_test");
if(ret)
{
printk(" error alloc_chrdev_region");
return ret ;
}

cdev_init(&test_cdev, &test_fops) ;
test_cdev.owner = THIS_MODULE ;
ret=cdev_add(&test_cdev, devID, 1);
if(unlikely(ret))
{
printk(" error cdev_add");
unregister_chrdev_region(devID,1);
return ret ;
}

test_class=class_simple_create(THIS_MODULE, "mmap_test");
if(unlikely(IS_ERR(test_class)))
printk(" error class_simple_create");
else
class_simple_device_add(test_class, devID, NULL, "mmap_test");

mem_pool_size= 2* PAGE_SIZE + (PAGE_SIZE>>1);//2.5 pages
mem_pool=(unsigned char*)__get_free_pages(GFP_KERNEL,get_order(mem_pool_size));
if(NULL == mem_pool)
{
if(likely(!(IS_ERR(test_class))))
{
class_simple_device_remove(devID);
class_simple_destroy(test_class);
}

cdev_del(&test_cdev);
unregister_chrdev_region(devID,1);
return 1 ;
}
*(unsigned int*)(mem_pool+PAGE_SIZE*0)=0x01234567;
*(unsigned int*)(mem_pool+PAGE_SIZE*1)=0x87654321;
*(unsigned int*)(mem_pool+PAGE_SIZE*2)=0xa5a5a5a5;


return 0 ;
}

static void __exit cleanup_test(void)
{
printk(" exit:0x%p 0x%p 0x%p",
(void*)*(unsigned int*)(mem_pool+PAGE_SIZE*0),
(void*)*(unsigned int*)(mem_pool+PAGE_SIZE*1),
(void*)*(unsigned int*)(mem_pool+PAGE_SIZE*2));

free_pages((unsigned long)mem_pool, get_order(mem_pool_size));
if(likely(!(IS_ERR(test_class))))
{
class_simple_device_remove(devID);
class_simple_destroy(test_class);
}

cdev_del(&test_cdev);
unregister_chrdev_region(devID,1);
}

module_init(initialization_test);
module_exit(cleanup_test);
MODULE_LICENSE("GPL");



下面是测试应用代码
//app
#include<sys/mman.h>
#include<sys/types.h>
#include<fcntl.h>
#include<unistd.h>

int main(void)
{
int fd;
char*content;
unsigned int* a,*b,*c;
fd=open("/dev/mmap_test",O_RDWR);
if(-1 == fd)
{
printf(" open error!") ;
return 0 ;
}
content=(char*)mmap(NULL,2.5*4*1024,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
if(NULL == content)
{
printf(" mmap error!") ;
close(fd) ;
return 0 ;
}
a=((unsigned int *)content);
b=((unsigned int *)(content+4*1024));
c=((unsigned int *)(content+8*1024));
printf(" a=%p ",(void *)*a);
printf(" b=%p ",(void *)*b);
printf(" c=%p ",(void *)*c);

*a= 0x85214715 ;
*b= 0x12312314 ;
*c= 0x94561200 ;

printf(" a=%p ",(void *)*a);
printf(" b=%p ",(void *)*b);
printf(" c=%p ",(void *)*c);

munmap(content,2.5*4*1024);
close(fd);
return 0;
}
[Original] [Print] [Top]
Subject: Re: nopage多页映射出错,请教!
Author: wheelz    Posted: 2007-11-25 01:14    Length: 456 byte(s)
[Original] [Print] [Top]
1)
函数test_vma_nopage()里面
offset=address-vma->vm_start+(vma->vm_pgoff << PAGE_SHIFT) ;
是错误的,应该是
offset=address-vma->vm_start;

2)
__get_free_pages()获得的page,只有第一个page的计数增加了,后面的page的_count是不对的。
可以每次分配一个页面。

3)
app里面mmap()的返回值的判断应该和MAP_FAILED比较。
----
[Original] [Print] [Top]
Subject: Re: nopage多页映射出错,请教!
Author: ywfscu    Posted: 2007-11-25 19:53    Length: 481 byte(s)
[Original] [Print] [Top]
其实我的需求是这样的,我需要一段连续的物理内存,然后应用程序通过对该设备的fd调用mmap能访问到该连续物理内存。
当然可以在系统启动时预留一段内存,在驱动的mmap函数中用remap_page_range映射到进程虚拟空间。

该连续内存有3M左右大小。

我设想是在模块初始化时用__get_free_pages申请所有需要的连续空间,然后在缺页时用nopage函数返回所需页的struct page*

但是目前看来好像不行,那解释一下到底该如何做?

非常感谢!
[Original] [Print] [Top]
Subject: Re: nopage多页映射出错,请教!
Author: wheelz    Posted: 2007-11-25 20:29    Length: 480 byte(s)
[Original] [Print] [Top]
1)就你的需求,为什么要连续的物理内存呢?不连续的物理内存,也可以用nopage映射到连续的用户态空间啊.
这样,你只需要在模块初始化函数中,用alloc_page()分配多个单页面,再在nopage中一一返回这些页面。

2)用__get_free_pages()也是可以的。你需要在调用__get_free_pages()后,对每个申请到的页面,atomic_inc(&page->_count),即可。
当然,这个办法有点hackish。

另外,既然你的缓冲有3M这么大,我觉得remap_page_range也可以考虑。
----
[Original] [Print] [Top]
« Previous thread
CONFIG_DISCONTIGMEM 与 CONFIG_NUMA 有甚么关系?
Linux内核技术
18
Next thread »
[经验分享]大家都怎么学些内核知识的?
     

Copyright © 2007~2009 UNIX Resources Network, All Rights Reserved.      About URN | Privacy & Legal | Help | Contact us
webmaster: webmaster@unixresources.net
This page created on 2009-09-07 16:26:33, cost 0.0305540561676 ms.