{
if (prot == PROT_EXEC) {
pkey = execute_only_pkey(mm);
/* Obtain the address to map to. we verify (or select) it and ensure * that it represents a valid section of the address space. */
addr = get_unmapped_area(file, addr, len, pgoff, flags); if (offset_in_page(addr))
returnaddr;
/* Too many mappings? */
if (mm->map_count > sysctl_max_map_count)
return -ENOMEM; /* offset overflow? */
if ((pgoff + (len>> PAGE_SHIFT)) return -EOVERFLOW; /* Careful about overflows.. */ len = PAGE_ALIGN(len); if (!len) return -ENOMEM; if (!(flags& MAP_FIXED)) addr = round_hint_to_min(addr); /* * Does the application expect PROT_READ to imply PROT_EXEC? * * (the exception is when the underlying filesystem is noexec * mounted, in which case we dont add PROT_EXEC.) */ if ((prot& PROT_READ) && (current->personality & READ_IMPLIES_EXEC)) if (!(file&& path_noexec(&file->f_path))) prot |= PROT_EXEC; if (!len) return -EINVAL; *populate = 0; structmm_struct *mm = current->mm; int pkey = 0; } if (pkey < 0) pkey = 0; /* 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_prot_bits(prot, pkey) | calc_vm_flag_bits(flags) | mm->def_flags | VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC; if (flags& MAP_LOCKED) if (!can_do_mlock()) return -EPERM; if (mlock_future_check(mm, vm_flags, len)) return -EAGAIN; if (file) { switch (flags& MAP_TYPE) { case MAP_SHARED: if ((prot&PROT_WRITE) && !(file->f_mode&FMODE_WRITE)) /* * Make sure we don't allow writing to an append-only * file.. */ if (IS_APPEND(inode) && (file->f_mode & FMODE_WRITE)) /* * Make sure there are no mandatory locks on the file. */ if (locks_verify_locked(file)) return -EAGAIN; return -EACCES; return -EACCES; structinode *inode = file_inode(file); vm_flags |= VM_SHARED | VM_MAYSHARE; if (!(file->f_mode & FMODE_WRITE)) vm_flags&= ~(VM_MAYWRITE | VM_SHARED); /* fall through */ } /* case MAP_PRIVATE: if (!(file->f_mode & FMODE_READ)) } if (!file->f_op->mmap) return -ENODEV; return -EINVAL; if (vm_flags& (VM_GROWSDOWN|VM_GROWSUP)) break; return -EACCES; if (vm_flags& VM_EXEC) return -EPERM; vm_flags&= ~VM_MAYEXEC; if (path_noexec(&file->f_path)) { default: } switch (flags& MAP_TYPE) { case MAP_SHARED: } if (vm_flags& (VM_GROWSDOWN|VM_GROWSUP)) /* * Ignore pgoff. */ pgoff = 0; vm_flags |= VM_SHARED | VM_MAYSHARE; break; /* * Set pgoff according to addr for anon_vma. */ pgoff = addr>> PAGE_SHIFT; break; return -EINVAL; return -EINVAL; return -EINVAL; } else { case MAP_PRIVATE: default: * Set 'VM_NORESERVE' if we should not account for the * memory use of this mapping. */ } if (flags& MAP_NORESERVE) { } addr = mmap_region(file, addr, len, vm_flags, pgoff); if (!IS_ERR_VALUE(addr) && ((vm_flags& VM_LOCKED) || (flags& (MAP_POPULATE | MAP_NONBLOCK)) == MAP_POPULATE)) *populate = len; returnaddr; /* We honor MAP_NORESERVE if allowed to overcommit */ if (sysctl_overcommit_memory != OVERCOMMIT_NEVER) vm_flags |= VM_NORESERVE; /* hugetlb applies strict overcommit unless MAP_NORESERVE */ if (file&& is_file_hugepages(file)) vm_flags |= VM_NORESERVE; 算法伪代码: do_mmap() { 判断是否隐藏了可执行属性; 该虚拟区间的地址是否必须有参数addr指定,若不是,重新获取addr地址; 检测要映射的文件部分的长度是否是页对齐; offset是否越界; 映射数量限制; 获得一个一个未映射区间的起始地址,并检查是否是页大小对齐的,即低12位必须*为0; 获取文件相关节点inode; 如果file结构指针为0,则目的仅在于创建虚拟区间,或者说,并没有真正的映射*发生;如果file结构指针不为0,则目的在于建立从文件到虚拟区间的映射,那就要*根据标志指定的映射种类,把为文件设置的访问权考虑进去; 判断输入的欲映射的起始地址是否小于最小映射地址,如果小于,将addr修改为最小地址,不过前提是MAP_FIXED旗标没有设置; 查找没有映射过的空洞内存区,返回值addr就是这段空洞的起始地址; 对vm_flags进行设置,由参数flags确定vma线性区的flags,是共享还是私有; 创建vma,mmap_region(); } (4)mmap_region()代码如下: unsignedlong mmap_region(structfile *file, unsignedlongaddr, { structmm_struct *mm = current->mm; structvm_area_struct *vma, *prev; unsignedlonglen, vm_flags_t vm_flags, unsignedlongpgoff) int error; structrb_node **rb_link, *rb_parent; unsignedlong charged = 0; /* Check against address space limit. */ if (!may_expand_vm(mm, vm_flags, len>> PAGE_SHIFT)) { } /* Clear old maps */ while (find_vma_links(mm, addr, addr + len, &prev, &rb_link, } /* * Private writable mapping: check memory availability */ if (accountable_mapping(file, vm_flags)) { } /* * Can we just expand an old mapping? */ vma = vma_merge(mm, prev, addr, addr + len, vm_flags, NULL, file, pgoff, NULL, NULL_VM_UFFD_CTX); if (vma) goto out; charged = len>> PAGE_SHIFT; if (security_vm_enough_memory_mm(mm, charged)) return -ENOMEM; vm_flags |= VM_ACCOUNT; &rb_parent)) { return -ENOMEM; if (do_munmap(mm, addr, len)) unsignedlong nr_pages; /* * MAP_FIXED may remove pages of mappings that intersects with * requested mapping. Account for the pages it would unmap. */ nr_pages = count_vma_pages_range(mm, addr, addr + len); if (!may_expand_vm(mm, vm_flags, (len>> PAGE_SHIFT) - nr_pages)) return -ENOMEM; 百度搜索“77cn”或“免费范文网”即可找到本站免费阅读全部范文。收藏本站方便下次阅读,免费范文网,提供经典小说综合文库linux内核虚拟内存管理算法(2)在线全文阅读。
相关推荐: