首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

缺页异常详解(3)

缺页异常详解(3)

if (in_atomic() || !mm)                   goto no_context;
         /*
          * As per x86, we may deadlock here.  However, since the kernel only
          * validly references user space from well defined areas of the code,
          * we can bug out early if this is from code which shouldn't.
          */
         if (!down_read_trylock(&mm->mmap_sem)) {
                   if (!user_mode(regs) && !search_exception_tables(regs->ARM_pc))
                            goto no_context;
                   down_read(&mm->mmap_sem);
         } else {
                   /*
                    * The above down_read_trylock() might have succeeded in
                    * which case, we'll have missed the might_sleep() from
                    * down_read()
                    */
                   might_sleep();
#ifdef CONFIG_DEBUG_VM
                   if (!user_mode(regs) &&
                       !search_exception_tables(regs->ARM_pc))
                            goto no_context;
#endif
         }
         fault = __do_page_fault(mm, addr, fsr, tsk);
         up_read(&mm->mmap_sem);
         /*
          * Handle the "normal" case first - VM_FAULT_MAJOR / VM_FAULT_MINOR
          */
         /*如果返回值fault不是这里面的值,那么应该会是VM_FAULT_MAJORVM_FAULT_MINOR,说明问题解决了,返回,一般正常情况下,__do_page_fault的返回值fault会是0(VM_FAULT_MINOR)或者其他一些值,都不是下面之后会看到的这些*/
         if (likely(!(fault & (VM_FAULT_ERROR | VM_FAULT_BADMAP | VM_FAULT_BADACCESS))))
                   return 0;
         /*如果faultVM_FAULT_OOM这个级别的错误,那么这要杀掉进程*/
         if (fault & VM_FAULT_OOM) {
                   /*
                    * We ran out of memory, call the OOM killer, and return to
                    * userspace (which will retry the fault, or kill us if we
                    * got oom-killed)
                    */
                   pagefault_out_of_memory();
                   return 0;
         }
         /*
          * If we are in kernel mode at this point, we
          * have no context to handle this fault with.
          */
         /*再次判断是否是内核空间出现了页异常,并且通过__do_page_fault没有没有解决,跳到到no_context*/
         if (!user_mode(regs))
                   goto no_context;
         /*下面两个情况,通过英文注释可以理解,

一个是无法修复,另一个是访问非法地址,都是要杀掉进程的错误*/

         if (fault & VM_FAULT_SIGBUS) {
                   /*
                    * We had some memory, but were unable to
                    * successfully fix up this page fault.
                    */
                   sig = SIGBUS;
                   code = BUS_ADRERR;
         } else {
                   /*
                    * Something tried to access memory that
                    * isn't in our memory map..
                    */
                   sig = SIGSEGV;
                   code = fault == VM_FAULT_BADACCESS ?
                            SEGV_ACCERR : SEGV_MAPERR;
         }
         /*给用户进程发送相应的信号,杀掉进程*/
         __do_user_fault(tsk, addr, fsr, sig, code, regs);
         return 0;
no_context:
    /*内核引发的异常处理,如修复不畅,内核也要杀掉*/
         __do_kernel_fault(mm, addr, fsr, regs);
         return 0;
}
首先看第一个重点,源码片段如下
/*1、判断当前是否是在原子操作中(中断、可延迟函数、临界区)发生的异常
  2、通过mm是否存在判断是否是内核线程,对于内核线程,进程描述符的mm总为NULL,一旦成立,说明是在内核态中发生的异常,跳到标号no_context*/
         if (in_atomic() || !mm)
                   goto no_context;
继承事业,薪火相传
返回列表