mmap是个既简单又好用的东西,对于读写文件,它减少了一次内存拷贝,对于内存申请,它可以方便的申请到大块内存,用于自己管理。今天就来说说mmap的实现。
mmap的原型是这样的:
void *mmap(void *addr, size_t length, int prot, int flags,
int fd, off_t offset);
它在内核里的样子是这样的:
SYSCALL_DEFINE6(mmap, unsigned long, addr, unsigned long, len,
unsigned long, prot, unsigned long, flags,
unsigned long, fd, unsigned long, off)
{
long error;
error = -EINVAL;
if (off & ~PAGE_MASK) //判断offset是否对齐到页大小,不是则返回-EINVAL退出
goto out;
error = sys_mmap_pgoff(addr, len, prot, flags, fd, off >> PAGE_SHIFT);
out:
return error;
}
这里调用了mmap_pgoff,不看代码都不知道有这个系统调用呢
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)) {
//文件映射
audit_mmap_fd(fd, flags);
if (unlikely(flags & MAP_HUGETLB))
return -EINVAL;
file = fget(fd); //获取file结构体
if (!file)
goto out;
if (is_file_hugepages(file))
len = ALIGN(len, huge_page_size(hstate_file(file)));//如果是hugetlbfs的文件,需要调整下len
} else if (flags & MAP_HUGETLB) {
//匿名映射大页内存
struct user_struct *user = NULL;
struct hstate *hs = hstate_sizelog((flags >> MAP_HUGE_SHIFT) &
SHM_HUGE_MASK);
if (!hs)
return -EINVAL;
len = ALIGN(len, huge_page_size(hs)); //如果是hugetlbfs的文件,需要调整下len
/*
* 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
*/
//如果是大页映射,则从hugetlbfs中创建一个名为anon_hugepage的file结构体来
file = hugetlb_file_setup(HUGETLB_ANON_FILE, len,
VM_NORESERVE,
&user, HUGETLB_ANONHUGE_INODE,
(flags >> MAP_HUGE_SHIFT) & MAP_HUGE_MASK);
if (IS_ERR(file))
return PTR_ERR(file);
}
flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); //这一行,目前还不懂它的用意在哪里,但并不影响我们分析 mmap代码,要是后面弄懂了呢:)
//文件映射、匿名映射都会调到这里来
retval = vm_mmap_pgoff(file, addr, len, prot, flags, pgoff);
if (file)
fput(file);
out:
return retval;
}
mmap_pgoff里主要是做了些准备,然后调用vm_mmap_pgoff进行映射,这个函数的用途是对进程的虚拟地址空间进行映射, 它的定义位于mm/util.c说明它个通用的工具函数。
unsigned long vm_mmap_pgoff(struct file *file, unsigned long addr,
unsigned long len, unsigned long prot,
unsigned long flag, unsigned long pgoff)
{
unsigned long ret;
struct mm_struct *mm = current