- 論壇徽章:
- 0
|
本帖最后由 cluter 于 2011-06-05 15:32 編輯
只講大體流程,不過分追究細節(jié)了,因為細節(jié)我也沒全搞懂,所以只能先整體上把握了。。。 希望大牛指正!- //******************************copy_mm**********************************************
- static int copy_mm(unsigned long clone_flags, struct task_struct * tsk)
- {
- // 1 如果內(nèi)存空間共享,直接增加內(nèi)存描述符mm的引用計數(shù),然后退出
- if (clone_flags & CLONE_VM) {
- atomic_inc(&oldmm->mm_users);
- mm = oldmm;
- goto good_mm;
- }
- // 2 如果內(nèi)存空間不共享,則創(chuàng)建一個新的內(nèi)存空間
- mm = dup_mm(tsk);
- good_mm:
- // 3 對于進程來說mm和active_mm指向同一內(nèi)存描述符mm
- // 對于內(nèi)核線程來說,使用active_mm指向當前進程的內(nèi)存描述符mm
- // 內(nèi)核線程不使用線性區(qū)
- tsk->mm = mm;
- tsk->active_mm = mm;
- return 0;
- }
- struct mm_struct *dup_mm(struct task_struct *tsk)
- {
- // 1 為新進程分配一個新的內(nèi)存描述符mm
- mm = allocate_mm();
- // 2 先拷貝父進程內(nèi)存描述符的所有內(nèi)容
- memcpy(mm, oldmm, sizeof(*mm));
- // 3 初始化新內(nèi)存描述符mm中的字段(包括為新進程分配一個新的pgd)
- if (!mm_init(mm, tsk))
- goto fail_nomem;
- // 4 復(fù)制父進程的線性區(qū)間和頁表
- err = dup_mmap(mm, oldmm);
- }
- // 1 分配新的vma線性區(qū)并初始化
- // 2 如果vma線性區(qū)是file 映射則加入priority-search tree
- // 3 把新的vma線性區(qū)加入內(nèi)存描述符mm的red-black tree
- // 4 鏈接vma線性區(qū)間
- // 5 復(fù)制頁表項
- static int dup_mmap(struct mm_struct *mm, struct mm_struct *oldmm)
- {
- struct vm_area_struct *mpnt, *tmp, *prev, **pprev;
- struct rb_node **rb_link, *rb_parent;
- int retval;
- unsigned long charge;
- struct mempolicy *pol;
- //獲取鎖
- down_write(&oldmm->mmap_sem);
- flush_cache_dup_mm(oldmm);
- /*
- * Not linked in yet - no deadlock potential:
- */
- down_write_nested(&mm->mmap_sem, SINGLE_DEPTH_NESTING);
- //初始化mm描述符
- mm->locked_vm = 0;
- mm->mmap = NULL;
- mm->mmap_cache = NULL;
- mm->free_area_cache = oldmm->mmap_base;
- mm->cached_hole_size = ~0UL;
- mm->map_count = 0;
- cpumask_clear(mm_cpumask(mm));
- mm->mm_rb = RB_ROOT;
- rb_link = &mm->mm_rb.rb_node;
- rb_parent = NULL;
- pprev = &mm->mmap;
- retval = ksm_fork(mm, oldmm);
- if (retval)
- goto out;
- prev = NULL;
- //開始復(fù)制vma線性區(qū)
- for (mpnt = oldmm->mmap; mpnt; mpnt = mpnt->vm_next) {
- struct file *file;
- //線性區(qū)間不允許拷貝
- if (mpnt->vm_flags & VM_DONTCOPY) {
- long pages = vma_pages(mpnt);
- //那么進程地址空間大小就要減去該線性區(qū)間
- mm->total_vm -= pages;
- vm_stat_account(mm, mpnt->vm_flags, mpnt->vm_file,
- -pages);
- continue;
- }
- charge = 0;
- //IPC共享線性區(qū),檢查是否有足夠的內(nèi)存用于映射
- if (mpnt->vm_flags & VM_ACCOUNT) {
- unsigned int len = (mpnt->vm_end - mpnt->vm_start) >> PAGE_SHIFT;
- if (security_vm_enough_memory(len))
- goto fail_nomem;
- charge = len;
- }
- //分配一個新的vma線性區(qū)
- tmp = kmem_cache_alloc(vm_area_cachep, GFP_KERNEL);
- if (!tmp)
- goto fail_nomem;
- //復(fù)制內(nèi)容
- *tmp = *mpnt;
- INIT_LIST_HEAD(&tmp->anon_vma_chain);
- pol = mpol_dup(vma_policy(mpnt));
- retval = PTR_ERR(pol);
- if (IS_ERR(pol))
- goto fail_nomem_policy;
- vma_set_policy(tmp, pol);
- if (anon_vma_fork(tmp, mpnt))
- goto fail_nomem_anon_vma_fork;
- tmp->vm_flags &= ~VM_LOCKED;
- tmp->vm_mm = mm;
- tmp->vm_next = tmp->vm_prev = NULL;
- file = tmp->vm_file;
- //該vma線性區(qū)是否是文件映射
- if (file) {
- //獲取該文件映射對應(yīng)的address_space
- struct inode *inode = file->f_path.dentry->d_inode;
- struct address_space *mapping = file->f_mapping;
- get_file(file);
- if (tmp->vm_flags & VM_DENYWRITE)
- atomic_dec(&inode->i_writecount);
- spin_lock(&mapping->i_mmap_lock);
- if (tmp->vm_flags & VM_SHARED)
- mapping->i_mmap_writable++;
- tmp->vm_truncate_count = mpnt->vm_truncate_count;
- flush_dcache_mmap_lock(mapping);
- /* insert tmp into the share list, just after mpnt */
- //新的vma線性區(qū)直接插入priority-search tree
- //priority-search tree主要用于頁框回收時,釋放所有映射該頁框的頁表項
- vma_prio_tree_add(tmp, mpnt);
- flush_dcache_mmap_unlock(mapping);
- spin_unlock(&mapping->i_mmap_lock);
- }
- /*
- * Clear hugetlb-related page reserves for children. This only
- * affects MAP_PRIVATE mappings. Faults generated by the child
- * are not guaranteed to succeed, even if read-only
- */
- if (is_vm_hugetlb_page(tmp))
- reset_vma_resv_huge_pages(tmp);
- /*
- * Link in the new vma and copy the page table entries.
- */
- //把剛分配的vma線性區(qū)鏈接起來
- *pprev = tmp;
- pprev = &tmp->vm_next;
- tmp->vm_prev = prev;
- prev = tmp;
- //把新分配的vma線性區(qū)插入red-black tree
- __vma_link_rb(mm, tmp, rb_link, rb_parent);
- rb_link = &tmp->vm_rb.rb_right;
- rb_parent = &tmp->vm_rb;
- mm->map_count++;
- //拷貝頁表項
- retval = copy_page_range(mm, oldmm, mpnt);
- if (tmp->vm_ops && tmp->vm_ops->open)
- tmp->vm_ops->open(tmp);
- if (retval)
- goto out;
- }
- /* a new mm has just been created */
- arch_dup_mmap(oldmm, mm);
- retval = 0;
- out:
- up_write(&mm->mmap_sem);
- flush_tlb_mm(oldmm);
- up_write(&oldmm->mmap_sem);
- return retval;
- fail_nomem_anon_vma_fork:
- mpol_put(pol);
- fail_nomem_policy:
- kmem_cache_free(vm_area_cachep, tmp);
- fail_nomem:
- retval = -ENOMEM;
- vm_unacct_memory(charge);
- goto out;
- }
- //************copy_page_range**********************
- //調(diào)用流程
- copy_page_range
- |
- |
- |
- copy_pud_range
- |
- |
- |
- copy_pmd_range
- |
- |
- |
- copy_pte_range
- |
- |
- |
- copy_one_pte
- //對于copy_one_pte有兩個重要的地方
- // 最開始是關(guān)于如果頁表所映射的頁框已經(jīng)在swap中的處理過程
- // 1 如果是copy on write映射,則父子頁表都要寫保護
- /*
- * If it's a COW mapping, write protect it both
- * in the parent and the child
- */
- if (is_cow_mapping(vm_flags)) {
- ptep_set_wrprotect(src_mm, addr, src_pte);
- pte = pte_wrprotect(pte);
- }
- // 2 如果是共享映射 ,則清空子進程頁表項,屬于請求調(diào)頁
- [size=7][color=Magenta] //如果是共享映射,為啥不直接負責(zé)頁表項,而是清空子進程頁表項?[/color][/size]
- /*
- * If it's a shared mapping, mark it clean in
- * the child
- */
- if (vm_flags & VM_SHARED)
- pte = pte_mkclean(pte);
- pte = pte_mkold(pte);[color=Red][size=7]------>這里標記頁表被訪問過是啥意思?[/size][/color]
復(fù)制代碼 |
評分
-
查看全部評分
|