- 论坛徽章:
- 0
|
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(¤t->mm->mmap_sem);
60 error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
61 up_write(¤t->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 |
|