mmap

原创:kylin_zeng  http://blog.sina.com.cn/u/2312748742

一、
mmap系统调用:
1)void *mmap(void *addr,size_t len, int prot, int flags, int fd, off_t offset);
2)功能:内存映射函数mmap将文件内容映射到进程的虚拟内存空间中,可以通过读取和更改这段内存从而间接改文件。
3)参数:addr: 指定映射的起始地址,可设null由系统指定
          len:映射到内存的文件长度。
          prot:映射区的保护。PROT_EXEC:可执行,PROT_READ:可读,PROT_WRITE:可写
flags:映射区的特性:MAP_SHARED:映射区更改文件也会更改,且允许其他映射该文件的进程共享。
                    MAP_PRIVATE:不会对文件更改。
4)返回值:返回虚拟的内存空间:void *mmap。
munmap解除映射:
1)int munmap(void *start,size_t length);
2)功能:取消start所指的length长度的映射内存。
3)参数:start,有void *mmap返回的值。length长度。
4)返回值:解除成功0,否则-1,错误原因在errno中。

注意:最终文件的内容大小不会改变。

二、虚拟内存区域:
1)虚拟内存区域是进程的虚拟地址空间中的一个同质区间,即具有同样特性的连续地址范围。
内存映像由:程序代码,数据,BSS,栈区域,内存映射区域组成。
也就是比如栈为一个虚拟内存区域,堆为一个,初始化数据为一个等等。
一个进程内存区域可以通过 cat /proc/pid/maps查看。
2)如:08048000-0804f000 r-xp 00000000 08:01 573748 /sbin/rpc.statd #test
    start :区域的起始虚拟地址;
    end:结束虚拟地址:
    perm:表示对这个区域运行进程做什么,有读写和执行等权限。最后一个字符p表示私有的,s表示共享
    offset:被映射部分在文件中的起始地址。
    major,minor:主次设备号。
inode:索引节点。
3)在linux内核使用vm_area_struct()来描述虚拟内存区
有几个成员:unsigned long vm_start:虚拟内存区的起始地址;
unsigned long vm_end;结束。
unsigned long vm_flags:有VM_IO 将vma标记为内存映射的io区域。
VM_RESERVED标记内存区域不能被换出。

三、mmap设备的操作:
    映射一个设备是指:将用户空间的一段地址关联到设备内存中。单程序读这个用户空间的地址时
就是在访问设备。
    mmap设备方法要完成这个功能实际要做就是建立虚拟地址到物理地址的页表。
int(*mmap)(struct file *,struct vm_area_struct*)
    mmap如何完成页表的建立:
    1)remap_pfn_range(struct vm_area_struct* vma,unsigened long addr,
    unsigned long pfn,unsigned long size,pgprot_t prot)一次建立所有的页表。
    vma:虚拟内存区域指针,
    virt_addr:虚拟地址的起始值
    pfn:要映射的物理地址所在物理页的帧号。物理地址>>PAGE_SHIFT(页大小)得到
    size:要映射的区域大小
    prot:vma保护属性。
    例如:
    int memdev_mmap(struct file *filp,struct vm_area_struct*vma)
    {
    vma->vm_flags |=VM_IO;
    vma->vm_flags |=VM_RESERVED;
    if(remap_pfn_range(vma,vma->vm_start,
        virt_to_phys(dev->data)>>PAGE_SHIFT,
        size,
        vma->vm_page_prot))
       
        return -EAGAIN;
   
    return 0;
    }
   
    2)nopage vma每次建立一个页表。
   

四、访问物理地址:
操作io内存:
申请,映射,访问,释放。
申请io内存:
    struct resource *request_mem_region(unsigned long start,unsigned long len,char *name);
申请一个从start开始,长度为len的字节内存区。成功返回非0,失败返回0.
所以的io内存在/proc/inmem中列出。
    在访问io内存前必须先进行物理地址到虚拟地址的映射,:
void *ioremap(unsigned long phys_addr,unsigned long size);
    读io 内存:
    unsigned ioread8(void *addr);//8位 老版本 ioreadb ioreadw ioreadl
    unsigned ioread16(void *addr);//16位 
    unsigned ioread32(void *addr);//32位 
    写io内存:
    unsigned ioread8(u8 value,void *addr);//8位 
    unsigned ioread16(u8 value,void *addr);//16位 
    unsigned ioread32(u8 value,void *addr);//32位 
    释放io内存:
    void iounmap(void *addr);
    void release_mem_region(unsigned long start,unsigned long len);
   
**********************************************************************************
五、混杂设备 miscdevice:一类字符设备它们共享一个主设备(10),但次设备号不同。
                                      所以的混杂设备形成一个链表,内核根据次设备号查找相应的miscdevice设备。
struct miscdevice{
  int minor;//次设备号
  const char *name; //设备名
  const struct file_operations *fops;//文件操作
  struct list_head list;
  sturct device *parent;
  struct device *this_device;
};
注册用:int misc_register(struct miscdevice *misc);
例如:注册led:
1)ret = misc_register(&misc);   
2)static struct miscdevice misc = {
  .minor = MISC_DYNAMIC_MINOR, //这个是255 表示由系统动态分配一个次设备号
  .name = "led",
  .fops = &dev_fops,    //字符设备都要有fops.
};
                   
3)static struct file_operations dev_fops = {
  .owner  THIS_MODULE,
  .ioctl  sbc2440_leds_ioctl,  //支持ioctl.内核还自动设置open,和relese.
};
4)
static int sbc2440_leds_ioctl(
  struct inode *inode,
  struct file *file,
  unsigned int cmd,
  unsigned long arg)
{
  switch(cmd) {
  case 0:
  case 1:
    if (arg > 4) {
      return -EINVAL;
    }
    s3c2410_gpio_setpin(led_table[arg], !cmd);
    return 0;
  default:
    return -EINVAL;
  }
}
ioctl一般可以两步:定义命令和实现命令。这里比较简单没这样做。
说明:sscanf(argv[1], "%d", &led_no) != 1 这个表示 将argv[1]收到的字符串转换成%d整形然后赋给led_no.




   
           
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
***种原因。根据引用,在Linux环境下,mmap是一种文件访问的优化手段。当系统限制进程可使用的mmap数量达到上限时,会导致mmap失败。为了解决这个问题,可以通过调整系统参数来增加可使用的mmap数量,具体的调整方式是编辑/etc/sysctl.conf文件并添加以下内容:vm.max_map_count = 1048575。这样可以扩大可使用的mmap数量,从而解决mmap失败的问题。 另外,根据引用,当mmap函数发生错误时,它会返回MAP_FAILED或-1。所以在代码中,应该检查mmap函数的返回值是否为0来判断是否发生错误。 此外,引用还提到了可能由于文件只读却在mmap中使用了PROT_READ | PROT_WRITE(读写)而导致mmap失败的情况。因此,在使用mmap时应确保文件的读写权限与mmap的参数相匹配,以避免mmap失败。 总结起来,mmap失败可能是因为系统限制了可使用的mmap数量,解决方法是调整系统参数。另外,在代码中应该检查mmap函数的返回值是否为0,以判断是否发生错误。此外,还应确保文件的读写权限与mmap的参数相匹配,以避免mmap失败。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [记Cassandra的OOM问题分析和解决(mmap failed)](https://blog.csdn.net/u013887254/article/details/107809312)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] - *2* [简单的shell脚本来检测mmap()返回值的错误检查-C/C++开发](https://download.csdn.net/download/weixin_42140710/19108465)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] - *3* [mmap失败时原因](https://blog.csdn.net/qq_16097611/article/details/51916275)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值