do_mmap()函数

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);  
  1. 首先对len进行页面对齐,检查对齐后的大小是否正确,如果错误直接返回addr。
  2. 调用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);
  1. 进行一系列安全检查,对内存检查,对于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;                                
  2. 检查页面偏移

       if ((pgoff + (len >> PAGE_SHIFT)) < pgoff)
           return -EINVAL;  
  3. 验证文件信息

       /* 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;
           }
       }
  4. 检查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;
  5. 继续检查………………

       /* 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;
                           }
  6. 进行文件映射

       /* allow the security API to have its say 进行API直接去映射*/
       ret =  _file_mmap(file, prot, flags);
       if (ret)
           return ret;
  7. 如果不能直接映射但是可以共享

       /* 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;
               }
           }
    

总归来说,尽力确保在现有的权限下将文件进行映射。

你可能感兴趣的:(mmap)