mmap/do_mmap/do_mmap_pgoff

mmap系统调用 返回新线性区中第一个单元位置的线性地址。注意:linux中有mmap(由老的C库使用)和mmap2(由新的C库使用)两个系统调用,他们仅在第6个参数有区别。(所在公司的平台上经测试用的都是mmap而非mmap2)

在linux-2.6.27.28中,系统调用mmap和mmap2都调用do_mmap2函数,do_mmap2函数再调用do_mmap_pgoff。
在linux-2.6.27.28/arch/mips/kernel/syscall.c中
SYSCALL_DEFINE6(mips_mmap, unsigned long, addr, unsigned long, len,
 unsigned long, prot, unsigned long, flags, unsigned long,
 fd, off_t, offset)
{
 unsigned long result;

 result = -EINVAL;
 if (offset & ~PAGE_MASK)
  goto out;

 result = do_mmap2(addr, len, prot, flags, fd, offset >> PAGE_SHIFT);

out:
 return result;
}
SYSCALL_DEFINE6(mips_mmap2, unsigned long, addr, unsigned long, len,
 unsigned long, prot, unsigned long, flags, unsigned long, fd,
 unsigned long, pgoff)
{
 if (pgoff & (~PAGE_MASK >> 12))
  return -EINVAL;

 return do_mmap2(addr, len, prot, flags, fd, pgoff >> (PAGE_SHIFT-12));
}
/* common code for old and new mmaps */
static inline unsigned long
do_mmap2(unsigned long addr, unsigned long len, unsigned long prot,
        unsigned long flags, unsigned long fd, unsigned long pgoff)
{
 unsigned long error = -EBADF;
 struct file * file = NULL;

 flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
 if (!(flags & MAP_ANONYMOUS)) {
  file = fget(fd);
  if (!file)
   goto out;
 }

 down_write(&current->mm->mmap_sem);
 error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
 up_write(&current->mm->mmap_sem);

 if (file)
  fput(file);
out:
 return error;
}
在linux-2.6.27.28/mm/mmap.c中有函数do_mmap_pgoff的实现

在linux-2.6.35中,系统调用mmap和mmap2都调用sys_mmap_pgoff,系统调用mmap_pgoff再调用,do_mmap2函数再调用do_mmap_pgoff。
在linux-2.6.35/arch/mips/kernel/syscall.c中
SYSCALL_DEFINE6(mips_mmap, unsigned long, addr, unsigned long, len,
 unsigned long, prot, unsigned long, flags, unsigned long,
 fd, off_t, offset)
{
 unsigned long result;

 result = -EINVAL;
 if (offset & ~PAGE_MASK)
  goto out;

 result = sys_mmap_pgoff(addr, len, prot, flags, fd, offset >> PAGE_SHIFT);

out:
 return result;
}

SYSCALL_DEFINE6(mips_mmap2, unsigned long, addr, unsigned long, len,
 unsigned long, prot, unsigned long, flags, unsigned long, fd,
 unsigned long, pgoff)
{
 if (pgoff & (~PAGE_MASK >> 12))
  return -EINVAL;

 return sys_mmap_pgoff(addr, len, prot, flags, fd, pgoff >> (PAGE_SHIFT-12));
}

在linux-2.6.35/mm/mmap.c中
SYSCALL_DEFINE6(mmap_pgoff, unsigned long, addr, unsigned long, len,
  unsigned long, prot, unsigned long, flags,
  unsigned long, fd, unsigned long, pgoff)
{
 struct file *file = NULL;
 unsigned long retval = -EBADF;

 if (!(flags & MAP_ANONYMOUS)) {
  if (unlikely(flags & MAP_HUGETLB))
   return -EINVAL;
  file = fget(fd);
  if (!file)
   goto out;
 } else if (flags & MAP_HUGETLB) {
  struct user_struct *user = NULL;
  /*
   * VM_NORESERVE is used because the reservations will be
   * taken when vm_ops->mmap() is called
   * A dummy user value is used because we are not locking
   * memory so no accounting is necessary
   */
  len = ALIGN(len, huge_page_size(&default_hstate));
  file = hugetlb_file_setup(HUGETLB_ANON_FILE, len, VM_NORESERVE,
      &user, HUGETLB_ANONHUGE_INODE);
  if (IS_ERR(file))
   return PTR_ERR(file);
 }

 flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);

 down_write(&current->mm->mmap_sem);
 retval = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
 up_write(&current->mm->mmap_sem);

 if (file)
  fput(file);
out:
 return retval;
}

 

do_mmap函数为当前进程创建并初始化一个新的线性区(do_unmap函数从当前进程的地址空间删除一个线性地址空间)。do_mmap也调用了do_mmap_pgoff

在include/linux/mm.h中:
static inline unsigned long do_mmap(struct file *file, unsigned long addr,
 unsigned long len, unsigned long prot,
 unsigned long flag, unsigned long offset)
{
 unsigned long ret = -EINVAL;
 if ((offset + PAGE_ALIGN(len)) < offset)
  goto out;
 if (!(offset & ~PAGE_MASK))
  ret = do_mmap_pgoff(file, addr, len, prot, flag, offset >> PAGE_SHIFT);
out:
 return ret;
}

 

下面进入正题,分析do_mmap_pgoff函数:

 

你可能感兴趣的:(linux,struct,user,File,UP,locking)