*参照元 [#cc520445] #backlinks *説明 [#b741f145] -パス: [[linux-2.6.33/mm/mmap.c]] -FIXME: これは何? --説明 **引数 [#ue41253b] -struct file *file -- --[[linux-2.6.33/file]] -unsigned long addr -- -unsigned long len -- -unsigned long flags -- -unsigned int vm_flags -- -unsigned long pgoff -- **返り値 [#w4132174] -long -unsigned long -- **参考 [#a1dae6d1] *実装 [#t5cc2978] unsigned long mmap_region(struct file *file, unsigned long addr, unsigned long len, unsigned long flags, unsigned int vm_flags, unsigned long pgoff) { struct mm_struct *mm = current->mm; struct vm_area_struct *vma, *prev; int correct_wcount = 0; int error; struct rb_node **rb_link, *rb_parent; unsigned long charged = 0; struct inode *inode = file ? file->f_path.dentry->d_inode : NULL; - --[[linux-2.6.33/current(global)]] --[[linux-2.6.33/mm_struct]] --[[linux-2.6.33/vm_area_struct]] --[[linux-2.6.33/rb_node]] --[[linux-2.6.33/inode]] /* Clear old maps */ error = -ENOMEM; - --[[linux-2.6.33/ENOMEM]] munmap_back: vma = find_vma_prepare(mm, addr, &prev, &rb_link, &rb_parent); if (vma && vma->vm_start < addr + len) { if (do_munmap(mm, addr, len)) return -ENOMEM; goto munmap_back; } - --[[linux-2.6.33/find_vma_prepare()]] --[[linux-2.6.33/do_munmap()]] /* Check against address space limit. */ if (!may_expand_vm(mm, len >> PAGE_SHIFT)) return -ENOMEM; - --[[linux-2.6.33/may_expand_vm()]] --[[linux-2.6.33/PAGE_SHIFT]] /* * Set 'VM_NORESERVE' if we should not account for the * memory use of this mapping. */ if ((flags & MAP_NORESERVE)) { /* 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; } - --[[linux-2.6.33/MAP_NORESERVE]] --[[linux-2.6.33/sysctl_overcommit_memory(global)]] --[[linux-2.6.33/OVERCOMMIT_NEVER]] --[[linux-2.6.33/VM_NORESERVE]] --[[linux-2.6.33/is_file_hugepages()]] /* * Private writable mapping: check memory availability */ if (accountable_mapping(file, vm_flags)) { charged = len >> PAGE_SHIFT; if (security_vm_enough_memory(charged)) return -ENOMEM; vm_flags |= VM_ACCOUNT; } - --[[linux-2.6.33/accountable_mapping()]] --[[linux-2.6.33/security_vm_enough_memory()]] --[[linux-2.6.33/VM_ACCOUNT]] /* * Can we just expand an old mapping? */ vma = vma_merge(mm, prev, addr, addr + len, vm_flags, NULL, file, pgoff, NULL); if (vma) goto out; - --[[linux-2.6.33/vma_merge()]] /* * Determine the object being mapped and call the appropriate * specific mapper. the address has already been validated, but * not unmapped, but the maps are removed from the list. */ vma = kmem_cache_zalloc(vm_area_cachep, GFP_KERNEL); if (!vma) { error = -ENOMEM; goto unacct_error; } - --[[linux-2.6.33/kmem_cache_zalloc()]] --[[linux-2.6.33/vm_area_cachep(global)]] --[[linux-2.6.33/GFP_KERNEL]] vma->vm_mm = mm; vma->vm_start = addr; vma->vm_end = addr + len; vma->vm_flags = vm_flags; vma->vm_page_prot = vm_get_page_prot(vm_flags); vma->vm_pgoff = pgoff; - --[[linux-2.6.33/vm_get_page_prot()]] if (file) { error = -EINVAL; if (vm_flags & (VM_GROWSDOWN|VM_GROWSUP)) goto free_vma; if (vm_flags & VM_DENYWRITE) { error = deny_write_access(file); if (error) goto free_vma; correct_wcount = 1; } - --[[linux-2.6.33/VM_GROWSDOWN]] --[[linux-2.6.33/VM_GROWSUP]] --[[linux-2.6.33/VM_DENYWRITE]] --[[linux-2.6.33/deny_write_access()]] vma->vm_file = file; get_file(file); error = file->f_op->mmap(file, vma); if (error) goto unmap_and_free_vma; if (vm_flags & VM_EXECUTABLE) added_exe_file_vma(mm); - --[[linux-2.6.33/get_file()]] --[[linux-2.6.33/VM_EXECUTABLE]] --[[linux-2.6.33/added_exe_file_vma()]] /* Can addr have changed?? * * Answer: Yes, several device drivers can do it in their * f_op->mmap method. -DaveM */ addr = vma->vm_start; pgoff = vma->vm_pgoff; vm_flags = vma->vm_flags; } else if (vm_flags & VM_SHARED) { error = shmem_zero_setup(vma); if (error) goto free_vma; - --[[linux-2.6.33/VM_SHARED]] --[[linux-2.6.33/shmem_zero_setup()]] } if (vma_wants_writenotify(vma)) { pgprot_t pprot = vma->vm_page_prot; /* Can vma->vm_page_prot have changed?? * * Answer: Yes, drivers may have changed it in their * f_op->mmap method. * * Ensures that vmas marked as uncached stay that way. */ vma->vm_page_prot = vm_get_page_prot(vm_flags & ~VM_SHARED); if (pgprot_val(pprot) == pgprot_val(pgprot_noncached(pprot))) vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); - --[[linux-2.6.33/pgprot_t]] --[[linux-2.6.33/vm_get_page_prot()]] --[[linux-2.6.33/pgprot_val()]] --[[linux-2.6.33/pgprot_noncached()]] } vma_link(mm, vma, prev, rb_link, rb_parent); file = vma->vm_file; - --[[linux-2.6.33/vma_link()]] /* Once vma denies write, undo our temporary denial count */ if (correct_wcount) atomic_inc(&inode->i_writecount); - --[[linux-2.6.33/atomic_inc()]] out: perf_event_mmap(vma); - --[[linux-2.6.33/perf_event_mmap()]] mm->total_vm += len >> PAGE_SHIFT; vm_stat_account(mm, vm_flags, file, len >> PAGE_SHIFT); - --[[linux-2.6.33/vm_stat_account()]] if (vm_flags & VM_LOCKED) { /* * makes pages present; downgrades, drops, reacquires mmap_sem */ long nr_pages = mlock_vma_pages_range(vma, addr, addr + len); if (nr_pages < 0) return nr_pages; /* vma gone! */ mm->locked_vm += (len >> PAGE_SHIFT) - nr_pages; } else if ((flags & MAP_POPULATE) && !(flags & MAP_NONBLOCK)) make_pages_present(addr, addr + len); return addr; - --[[linux-2.6.33/VM_LOCKED]] --[[linux-2.6.33/mlock_vma_pages_range()]] --[[linux-2.6.33/MAP_POPULATE]] --[[linux-2.6.33/MAP_NONBLOCK]] --[[linux-2.6.33/make_pages_present()]] unmap_and_free_vma: if (correct_wcount) atomic_inc(&inode->i_writecount); vma->vm_file = NULL; fput(file); - --[[linux-2.6.33/fput()]] /* Undo any partial mapping done by a device driver. */ unmap_region(mm, vma, prev, vma->vm_start, vma->vm_end); charged = 0; - --[[linux-2.6.33/unmap_region()]] free_vma: kmem_cache_free(vm_area_cachep, vma); - --[[linux-2.6.33/kmem_cache_free()]] unacct_error: if (charged) vm_unacct_memory(charged); return error; - --[[linux-2.6.33/vm_unacct_memory()]] } *コメント [#te4ca810]