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.com
  LinuxForum General Chat
  Linux Advocacy
  LinuxForum Polls
  Introductions
  Linux Kernel Support
  Patch Management
  Development Release
  Linux Programming
  Linux Security
  Linux Software
  Linux Hardware Problems
    Linux Video Problems
    Linux Sound Problems
  Linux Networking Support
  Linux Printing Support
  Linux Human Interface Devices Support
  Linux Data Storage Support
  Linux Applications Support
  Linux Installation Support
  Linux Laptops Support
  Linux Motherboard, Chipsets, CPU, Memory
  Miscellaneous
  Debian Linux Support
  Ubuntu Linux Support
  LiveCD Discussions
  Gentoo Linux Support
  Mandrake Linux Support
  Redhat / Fedora Linux Support
  Slackware Linux Support
  SuSE Linux Support
  CentOS Linux Support
  Linux Web Servers
  Linux DNS Servers
  Linux Database Servers
  Linux Email Servers
  Linux FTP Servers
  Linux Squid Proxy Server
  Linux Samba Help
  Linux cPanel Help
  Linux Ensim Help
  Linux Plesk Help
  Linux Webmin / Usermin Help
  Qmail Toaster Help
  Linux Games
  Windows Game Emulation
  Linux Discussions
  General Linux Discussions
  Red Hat Linux Discussions
  More Red Hat Linux Discussions
  Mandrake Linux Discussions
  Slackware Linux Discussions
  SuSE Linux Discussions
  Debian Discussions
  Samba Help
  Linux Security
  Linux Networking
  Gentoo Help
  Operating System Rant Forum
  Hardware Rants
   
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 © 2018 UNIX Resources Network, All Rights Reserved.    About URN | Privacy & Legal | Help | Contact us