do_mmap()函数
do_mmap主要是用来将虚拟内存与物理内存进行直接映射
其核心在于 error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
其核心函数便是这个do_mmap_pgoff函数
do_mmap_pgoff
unsigned long do_mmap_pgoff(struct file * file, unsigned long addr,
unsigned long len, unsigned long prot,
unsigned long flags, unsigned long pgoff);
- 首先对len进行页面对齐,检查对齐后的大小是否正确,如果错误直接返回addr。
- 调用do_mmap_pgoff(file, addr, len, prot, flag, offset >> PAGE_SHIFT);
unsigned long do_mmap_pgoff(struct file *file,
unsigned long addr,
unsigned long len,
unsigned long prot,
unsigned long flags,
unsigned long pgoff);
-
进行一系列安全检查,对内存检查,对于len的页面对齐长度检查。
if (flags & MAP_FIXED || addr) { printk(KERN_DEBUG "%d: Can't do fixed-address/overlay mmap of RAM\n", current->pid); return -EINVAL; } if (PAGE_ALIGN(len) == 0) return addr; if (len > TASK_SIZE) return -EINVAL; if (flags & MAP_FIXED || addr) { printk(KERN_DEBUG "%d: Can't do fixed-address/overlay mmap of RAM\n", current->pid); return -EINVAL; } if (PAGE_ALIGN(len) == 0) return addr; if (len > TASK_SIZE) return -EINVAL;
-
检查页面偏移
if ((pgoff + (len >> PAGE_SHIFT)) < pgoff) return -EINVAL;
-
验证文件信息
/* validate file mapping requests */ membacked = 0; if (file) { /* files must support mmap */ //检验文件是否支持mmap; if (!file->f_op || !file->f_op->mmap) return -ENODEV; if ((prot & PROT_EXEC) && (file->f_vfsmnt->mnt_flags & MNT_NOEXEC)) return -EPERM; //此处的检验?? //应该是对于memory backed的检验,不过我并不知道这个具体是什么,内存支持的文件? if (S_ISCHR(file->f_dentry->d_inode->i_mode)) { membacked = 1; } else { struct address_space *mapping = file->f_mapping; if (!mapping) mapping = file->f_dentry->d_inode->i_mapping; if (mapping && mapping->backing_dev_info) membacked = mapping->backing_dev_info->memory_backed; } //检查标志必须允许映射,也就是文件是共享的 if (flags & MAP_SHARED) { /* do checks for writing, appending and locking */ if ((prot & PROT_WRITE) && !(file->f_mode & FMODE_WRITE)) return -EACCES; if (IS_APPEND(file->f_dentry->d_inode) && (file->f_mode & FMODE_WRITE)) return -EACCES; if (locks_verify_locked(file->f_dentry->d_inode)) return -EAGAIN; if (!membacked) { printk("MAP_SHARED not completely supported on !MMU\n"); return -EINVAL; } if (!file->f_op->get_unmapped_area) return -ENODEV; } //否则是个私有文件的话我们将尽力把它去读取到内存中 else { /* we read private files into memory we allocate */ if (!file->f_op->read) return -ENODEV; } }
-
检查PROT中的标志,如果没有为其设置EXEC
/* handle PROT_EXEC implication by PROT_READ */ if ((prot & PROT_READ) && (current->personality & READ_IMPLIES_EXEC)) if (!(file && (file->f_vfsmnt->mnt_flags & MNT_NOEXEC))) prot |= PROT_EXEC;
-
继续检查………………
/* do simple checking here so the lower-level routines won't have * to. we assume access permissions have been handled by the open * of the memory object, so we don't do any here. */ vm_flags = calc_vm_flags(prot,flags) /* | mm->def_flags */ | VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC; if (!membacked) { /* share any file segment that's mapped read-only */ if (((flags & MAP_PRIVATE) && !(prot & PROT_WRITE) && file) || ((flags & MAP_SHARED) && !(prot & PROT_WRITE) && file)) vm_flags |= VM_MAYSHARE; /* refuse to let anyone share files with this process if it's being traced - * otherwise breakpoints set in it may interfere with another untraced process */ if (current->ptrace & PT_PTRACED) vm_flags &= ~(VM_SHARED | VM_MAYSHARE); } else { /* permit sharing of character devices and ramfs files at any time for * anything other than a privately writable mapping */ if (!(flags & MAP_PRIVATE) || !(prot & PROT_WRITE)) { vm_flags |= VM_MAYSHARE; if (flags & MAP_SHARED) vm_flags |= VM_SHARED; }
-
进行文件映射
/* allow the security API to have its say 进行API直接去映射*/ ret = _file_mmap(file, prot, flags); if (ret) return ret;
-
如果不能直接映射但是可以共享
/* we're going to need to record the mapping if it works */ vml = kmalloc(sizeof(struct vm_list_struct), GFP_KERNEL); if (!vml) goto error_getting_vml; memset(vml, 0, sizeof(*vml)); down_write(&nommu_vma_sem); /* if we want to share, we need to search for VMAs created by another * mmap() call that overlap with our proposed mapping * - we can only share with an exact match on most regular files * - shared mappings on character devices and memory backed files are * permitted to overlap inexactly as far as we are concerned for in * these cases, sharing is handled in the driver or filesystem rather * than here */ if (vm_flags & VM_MAYSHARE) { unsigned long pglen = (len + PAGE_SIZE - 1) >> PAGE_SHIFT; unsigned long vmpglen; for (rb = rb_first(&nommu_vma_tree); rb; rb = rb_next(rb)) { vma = rb_entry(rb, struct vm_area_struct, vm_rb); if (!(vma->vm_flags & VM_MAYSHARE)) continue; /* search for overlapping mappings on the same file */ if (vma->vm_file->f_dentry->d_inode != file->f_dentry->d_inode) continue; if (vma->vm_pgoff >= pgoff + pglen) continue; vmpglen = (vma->vm_end - vma->vm_start + PAGE_SIZE - 1) >> PAGE_SHIFT; if (pgoff >= vma->vm_pgoff + vmpglen) continue; /* handle inexact matches between mappings */ if (vmpglen != pglen || vma->vm_pgoff != pgoff) { if (!membacked) goto sharing_violation; continue; } /* we've found a VMA we can share */ atomic_inc(&vma->vm_usage); vml->vma = vma; result = (void *) vma->vm_start; goto shared; } }
总归来说,尽力确保在现有的权限下将文件进行映射。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。