- UID
- 133947
- 性别
- 男
|
*执行到这里,还有handle_mm_fault 返回-1的情况没有处理。
*VM_FAULT_MAJOR和VM_FAULT_SIGBUS的情况就直接返回了, *VM_FAULT_MINOR时,如果不是init进程请求缺页处理的话,也直 *接返回。
*但是,如果是init进程请求缺页,而且handle_mm_fault返回 *VM_FAULT_MINOR呢?我觉得是通过下面的循环再到 *handle_mm_fault分配一把物理页,但是由于这时候addr已经有物理 *页面,没必要也无法再分配物理页,因此handle_mm_fault会返回 *VM_FAULT_SIGBUS,然后直接return。我觉得这样分析是有问题的, *因为在返回VM_FAULT_SIGBUS到do_page_fault后,进程回被杀死, *Init进程能被杀死吗?
*/
/*
* If we are out of memory for pid1,
* sleep for a while and retry
*/
yield();
goto survive;
check_stack:
if (vma->vm_flags & VM_GROWSDOWN && !expand_stack(vma, addr))/*expand_stack 0 is ok expand both stack and mm of process*/
goto good_area;
out:
return fault;
}
/*
* By the time we get here, we already hold the mm semaphore
*/
int handle_mm_fault(struct mm_struct *mm, struct vm_area_struct * vma,
unsigned long address, int write_access)
{
pgd_t pgd;/*全局页目录表*/
pmd_t pmd;/*中间页表*/
__set_current_state(TASK_RUNNING);
pgd = pgd_offset(mm, address);/*获得在pgd中的偏移*/
inc_page_state(pgfault);
if (is_vm_hugetlb_page(vma))
return VM_FAULT_SIGBUS; /* mapping truncation does this. */
/*
* We need the page table lock to synchronize with kswapd
* and the SMP-safe atomic PTE updates.
*/
spin_lock(&mm->page_table_lock);
pmd = pmd_alloc(mm, pgd, address);/*分配一个新的中间页*/
if (pmd) {
pte_t * pte = pte_alloc_map(mm, pmd, address);/*分配页表*/
if (pte)
return handle_pte_fault(mm, vma, address, write_access, pte, pmd);
}
spin_unlock(&mm->page_table_lock);
return VM_FAULT_OOM;
}
static inline int handle_pte_fault(struct mm_struct *mm,
struct vm_area_struct * vma, unsigned long address,
int write_access, pte_t *pte, pmd_t *pmd)
{ pte_t entry;
entry = pte; /*取页帧目录项*/
if (!pte_present(entry))
{/*如果页帧不在物理内存中*/
if (pte_none(entry)) /*如果页帧目录项为空*/
return do_no_page(mm, vma, address, write_access, pte, pmd); 进行空页处理
if (pte_file(entry))
/*int pte_file(pte_t)是2.6的处理中新增加的一个inline函数,就是用来判别该页是否是映* 射到文件的。
* Return true if the pte is a "file pte". This is where you'll need to
* use the magical reserved bit to distinguish this from a swapped out pte.
* static inline int pte_file(pte_t pte) { return (pte).pte_low & _PAGE_FILE; }
* #define _PAGE_FILE 0x040 /* set:pagecache unset:swap */
*/
return do_file_page(mm, vma, address, write_access, pte, pmd);文件缓冲页处理
return do_swap_page(mm, vma, address, pte, pmd, entry, write_access); 进行换页处理
}
if (write_access)
{如果是访问权限的问题
if (!pte_write(entry))读/写权限都设置,才返回1
return do_wp_page(mm, vma, address, pte, pmd, entry);
进行写保护页处理
entry = pte_mkdirty(entry); 设置脏页标志
}
页在内存中,非空,非交换页,非文件缓冲页
entry = pte_mkyoung(entry); 设置访问标志
ptep_set_access_flags(vma, address, pte, entry, write_access);
/*
#define ptep_set_access_flags(__vma, __address, __ptep, __entry, __dirty)
do {
set_pte(__ptep, __entry); 将指定值写入表项
flush_tlb_page(__vma, __address);刷新TLB
} while (0)
*/
update_mmu_cache(vma, address, entry);
更新外部mm信息,x86,arm上是什么都不做.
pte_unmap(pte); //#define pte_unmap(pte) do { } while (0)
spin_unlock(&mm->page_table_lock);
return VM_FAULT_MINOR;
}
暂时就分析这么点,框图和原理在书上已经有了。关于init分配页返回1的情况,我的确无法解释为什么要这么安排,2.6.11;2.6.12都是这么处理,实在想不通。
|
51 c8051f(f020,f040) msp430 arm(2410,2510) fpga(xc3s4000) dsp(5116 dm642) keilc vc++ matlab linux protel Ten_layerPCB mpegx h.26x Rscode Turbocode ofdm VideoBroadcasting ldpc_code(now!) |
|