之前写了(一)(二)其实就梳理到了get_unmapped_area的内容,而且有一点混乱,这里进行第三篇的讲解,讲解在do_mmap_pgoff中除了get_unmapped_area的内容,来了解mmap的具体实现。通过(一)(二)(三)来将mmap内核源码进行一次梳理。可能过程有一点乱,所以最后准备写一篇总结来总结mmap这样一个流程。
(一)https://blog.csdn.net/SweeNeil/article/details/83685812
(二)https://blog.csdn.net/SweeNeil/article/details/83897094
在(三)中我准备从do_mmap_pgoff中的内容出发,分析(一)、(二)中没有分析的内容。
直接上do_mmap_pgoff函数的内容,/mm/mmap.c文件中的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,
unsigned long *populate)
{
struct mm_struct * mm = current->mm;
struct inode *inode;
vm_flags_t vm_flags;
*populate = 0;
/*
* 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.)
应用程序是否期望PROT_READ影射PROT_EXEC?
(例外情况是底层文件系统是noexec挂载的,
在这种情况下我们不添加PROT_EXEC)
*/
if ((prot & PROT_READ) && (current->personality & READ_IMPLIES_EXEC))
if (!(file && (file->f_path.mnt->mnt_flags & MNT_NOEXEC)))
prot |= PROT_EXEC;
if (!len)
return -EINVAL;
if (!(flags & MAP_FIXED))
addr = round_hint_to_min(addr);
/* 小心溢出 */
len = PAGE_ALIGN(len);
if (!len)
return -ENOMEM;
/* 溢出偏移? */
if ((pgoff + (len >> PAGE_SHIFT)) < pgoff)
return -EOVERFLOW;
/* 影射是否过多? */
if (mm->map_count > sysctl_max_map_count)
return -ENOMEM;
/* 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);
//如果现在都不是页对齐的,那么返回的肯定是错误码,返回之return addr
if (addr & ~PAGE_MASK)
return addr;
/* 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.
在这里进行简单的检查,以便下级例程不必。
我们假设访问权限已由内存对象的打开处理,
因此我们不在此处执行任何操作。
*/
//calc_vm_prot_bits 将mmap“prot”参数合并到内部使用的“vm_flags”中。
vm_flags = calc_vm_prot_bits(prot) | calc_vm_flag_bits(flags) |
mm->def_flags | VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC;
if (flags & MAP_LOCKED)
if (!can_do_mlock())
return -EPERM;
/* mlock MCL_FUTURE? */
if (vm_flags & VM_LOCKED) {
unsigned long locked, lock_limit;
locked = len >> PAGE_SHIFT;
locked += mm->locked_vm;
lock_limit = rlimit(RLIMIT_MEMLOCK);
lock_limit >>= PAGE_SHIFT;
if (locked > lock_limit && !capable(CAP_IPC_LOCK))
return -EAGAIN;
}
inode = file ? file_inode(file) : NULL;
if (file) {
switch (flags & MAP_TYPE) {
case MAP_SHARED:
if ((prot&PROT_WRITE) && !(file->f_mode&FMODE_WRITE))
return -EACCES;
/*
* M