免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 1839 | 回复: 0
打印 上一主题 下一主题

mm/mmap.c do_mmap_pgoff() [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2008-07-13 13:33 |只看该作者 |倒序浏览



mmap() > sys_mmap2() > do_mmap2()
(1) kernel/sys_i386.c
43 /* common code for old and new mmaps */
44 static inline long do_mmap2(
45         unsigned long addr, unsigned long len,
46         unsigned long prot, unsigned long flags,
47         unsigned long fd, unsigned long pgoff)
48 {
49         int error = -EBADF;
50         struct file * file = NULL;
51
52         flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
53         if (!(flags & MAP_ANONYMOUS)) {
54                 file = fget(fd);
55                 if (!file)
56                         goto out;
57         }
58
59         down_write(&current->mm->mmap_sem);
60         error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
61         up_write(&current->mm->mmap_sem);
62
63         if (file)
64                 fput(file);
65 out:
66         return error;
67 }
68
mmap将fd(file or other)偏移offset的长度为len的一段,映射到内存。addr
是用户向系统建议的起始地址. 真正的映射地址由系统调用返回,never 0.
  参数prot给出映射内的内存段的性质:
     PROT_EXEC, PROT_READ,PROT_WRITE,PROT_NONE(pages not be accessed).
  flags给出映射属性:
     MAP_FIXED:必须映射到用户指定的起始内存地址addr.(不鼓励使用)
     MAP_SHARED:这个映射和其他映射了相同fd的进程共享(即同一个页面影射到不同
进程,参考fault.c的分析,filmap.c的相关分析).写内存等于写文件,但是在调用msync或
者munmap之前文件不会被更新.
     MAP_PRIVATE:创建私有的COW映射,存储内存对原文件无影响.此选项没有定义
在映射后如果文件内容发生变化将会如何.
     MAP_EXECUTABLE,MAP_DENYWRITE: 不再使用了.ignore.
     MAP_NORESERVE:和MAP_PRIVATE共同使用.不为此映射保留swap紧急页,会导致
在内存缺乏的时候写内存操作引起SIGSEGV.
     MAP_LOCKED: ver〉2.5.37,同时进行mlock。
     MAP_GROWSDOWN:用于stack。
     MAP_ANONYMOUS:(same as MAP_ANON)无文件作为后备缓存。从linux2.4开始
实现了此标志和MAP_SHARED的联合使用。
     MAP_FILE: 兼容目的的flag。ignore。
     MAP_32BIT: X86-64,映射入处理器地址的头2G。
     
     如果映射出的内存页面有不足一页的情况,剩余的页面部分被清0,但是写相关
内存不会被写出到文件.如果已经影射的文件大小被改变了,效果未定.
(2)mm/mmap.c
建立起一个vma,设置vma->vm_ops, 使得缺页中断能够通过
vma->vm_ops->readpage从指定文件读取相关内容。
867 /*
868  * The caller must hold down_write(current->mm->mmap_sem).
869  */
870
871 unsigned long do_mmap_pgoff(struct file * file, unsigned long addr,
872                         unsigned long len, unsigned long prot,
873                         unsigned long flags, unsigned long pgoff)
874 {
884
885         //一些检查,mmap文件设备时.操作涵数是否有效. 大小与页面对齐. 不再内核空间映射. 进程没有过多映射等等.
925         addr = get_unmapped_area(file, addr, len, pgoff, flags);
926         if (addr & ~PAGE_MASK)
927                 return addr;
954         if (file) {
955                 switch (flags & MAP_TYPE) {
956                 case MAP_SHARED:
957                         if ((prot&PROT_WRITE) && !(file->f_mode&FMODE_WRITE))
958                                 return -EACCES;
959
960                         /*
961                          * Make sure we don't allow writing to an append-only
962                          * file..
963                          */
964                         if (IS_APPEND(inode) && (file->f_mode & FMODE_WRITE))
965                                 return -EACCES;
966
967                         /*
968                          * Make sure there are no mandatory locks on the file.
969                          */
970                         if (locks_verify_locked(inode))
971                                 return -EAGAIN;
972
973                         vm_flags |= VM_SHARED | VM_MAYSHARE;
974                         if (!(file->f_mode & FMODE_WRITE))
975                                 vm_flags &= ~(VM_MAYWRITE | VM_SHARED);
976
977                         /* fall through */
978                 case MAP_PRIVATE:
979                         if (!(file->f_mode & FMODE_READ))
980                                 return -EACCES;
981                         break;
982
983                 default:
984                         return -EINVAL;
985                 }
986         } else {
      }
1006         /* Clear old maps */
1007         error = -ENOMEM;
1008 munmap_back:
1009         vma = find_vma_prepare(mm, addr, &prev, &rb_link, &rb_parent);
1010         if (vma && vma->vm_start
1036         /*
1037          * Can we just expand an old private anonymous mapping?
1038          * The VM_SHARED test is necessary because shmem_zero_setup
1039          * will create the file object for a shared anonymous map below.
1040          */
1041         if (!file && !(vm_flags & VM_SHARED) &&
1042             vma_merge(mm, prev, addr, addr + len, vm_flags,
1043                                         NULL, NULL, pgoff, NULL))
1044                 goto out;
             //分配vma并填充
1051         vma = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL);
1052         if (!vma) {
1053                 error = -ENOMEM;
1054                 goto unacct_error;
1055         }
1056         memset(vma, 0, sizeof(*vma));
1062         vma->vm_page_prot = protection_map[vm_flags & 0x0f];
1063         vma->vm_pgoff = pgoff;
1064
1065         if (file) {
1066                 error = -EINVAL;
1067                 if (vm_flags & (VM_GROWSDOWN|VM_GROWSUP))
1068                         goto free_vma;
1069                 if (vm_flags & VM_DENYWRITE) {
1070                         error = deny_write_access(file);        /*禁止作为普通文件的写操作*/
1071                         if (error)
1072                                 goto free_vma;
1073                         correct_wcount = 1;
1074                 }
1075                 vma->vm_file = file;
1076                 get_file(file);
1077                 error = file->f_op->mmap(file, vma); //调用文件系统或设备相关的mmap()
         /*ext2就是generic_file_mmap
                                       *就是设置vma->vm_ops从而使
                                       *vma->vm_ops->readpage就是
                                       *filemap_nopage
                                       */
1078                 if (error)
1079                         goto unmap_and_free_vma;
1080         } else if (vm_flags & VM_SHARED) {
1081                 error = shmem_zero_setup(vma);             //
1082                 if (error)
1083                         goto free_vma;
1084         }
1103         if (!file || !vma_merge(mm, prev, addr, vma->vm_end,
1104                         vma->vm_flags, NULL, file, pgoff, vma_policy(vma))) {
1105                 file = vma->vm_file;
1106                 vma_link(mm, vma, prev, rb_link, rb_parent);  //连接
1107                 if (correct_wcount)
1108                         atomic_inc(&inode->i_writecount);
1109         } else {
1115                 mpol_free(vma_policy(vma));
1116                 kmem_cache_free(vm_area_cachep, vma);
1117         }
1118 out:   
1121         if (vm_flags & VM_LOCKED) {
1122                 mm->locked_vm += len >> PAGE_SHIFT;
1123                 make_pages_present(addr, addr + len);       //
1124         }
1125         if (flags & MAP_POPULATE) {
1126                 up_write(&mm->mmap_sem);
1127                 sys_remap_file_pages(addr, len, 0,
1128                                         pgoff, flags & MAP_NONBLOCK);
1129                 down_write(&mm->mmap_sem);
1130         }
1131         return addr;
1148 }
1149
1150 EXPORT_SYMBOL(do_mmap_pgoff);
(2)get_unmapped_area() 找出空闲线性地址空间
1331 unsigned long
1332 get_unmapped_area(struct file *file, unsigned long addr, unsigned long len,
1333                 unsigned long pgoff, unsigned long flags)
1334 {
1335         unsigned long ret;
1336
1337         if (!(flags & MAP_FIXED)) {
1338                 unsigned long (*get_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
1339
1340                 get_area = current->mm->get_unmapped_area;    //自己的
1341                 if (file && file->f_op && file->f_op->get_unmapped_area)
1342                         get_area = file->f_op->get_unmapped_area;  //文件系统提供
1343                 addr = get_area(file, addr, len, pgoff, flags);
1344                 if (IS_ERR_VALUE(addr))
1345                         return addr;
1346         }
1347
.....
.....
1366         if (ret)
1367                 return -EINVAL;
1368         return addr;
1369 }



本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u/17526/showart_1079658.html
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP