[PATCH 2/2] arm64/mm: add speculative page fault

kbuild test robot lkp at intel.com
Wed May 2 07:07:52 PDT 2018


Hi Ganesh,

Thank you for the patch! Yet something to improve:

[auto build test ERROR on arm64/for-next/core]
[also build test ERROR on v4.17-rc3 next-20180502]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url:    https://github.com/0day-ci/linux/commits/Ganesh-Mahendran/arm64-mm-define-ARCH_SUPPORTS_SPECULATIVE_PAGE_FAULT/20180502-183036
base:   https://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux.git for-next/core
config: arm64-defconfig (attached as .config)
compiler: aarch64-linux-gnu-gcc (Debian 7.2.0-11) 7.2.0
reproduce:
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # save the attached .config to linux build tree
        make.cross ARCH=arm64 

All errors (new ones prefixed by >>):

   arch/arm64/mm/fault.c: In function '__do_page_fault':
>> arch/arm64/mm/fault.c:329:15: error: implicit declaration of function 'can_reuse_spf_vma' [-Werror=implicit-function-declaration]
     if (!vma || !can_reuse_spf_vma(vma, addr))
                  ^~~~~~~~~~~~~~~~~
   arch/arm64/mm/fault.c: In function 'do_page_fault':
>> arch/arm64/mm/fault.c:416:11: error: implicit declaration of function 'handle_speculative_fault'; did you mean 'handle_mm_fault'? [-Werror=implicit-function-declaration]
      fault = handle_speculative_fault(mm, addr, mm_flags, &vma);
              ^~~~~~~~~~~~~~~~~~~~~~~~
              handle_mm_fault
>> arch/arm64/mm/fault.c:427:18: error: 'PERF_COUNT_SW_SPF' undeclared (first use in this function); did you mean 'PERF_COUNT_SW_MAX'?
       perf_sw_event(PERF_COUNT_SW_SPF, 1, regs, addr);
                     ^~~~~~~~~~~~~~~~~
                     PERF_COUNT_SW_MAX
   arch/arm64/mm/fault.c:427:18: note: each undeclared identifier is reported only once for each function it appears in
   cc1: some warnings being treated as errors

vim +/can_reuse_spf_vma +329 arch/arm64/mm/fault.c

   322	
   323	static int __do_page_fault(struct mm_struct *mm, unsigned long addr,
   324				   unsigned int mm_flags, unsigned long vm_flags,
   325				   struct task_struct *tsk, struct vm_area_struct *vma)
   326	{
   327		int fault;
   328	
 > 329		if (!vma || !can_reuse_spf_vma(vma, addr))
   330			vma = find_vma(mm, addr);
   331	
   332		vma = find_vma(mm, addr);
   333		fault = VM_FAULT_BADMAP;
   334		if (unlikely(!vma))
   335			goto out;
   336		if (unlikely(vma->vm_start > addr))
   337			goto check_stack;
   338	
   339		/*
   340		 * Ok, we have a good vm_area for this memory access, so we can handle
   341		 * it.
   342		 */
   343	good_area:
   344		/*
   345		 * Check that the permissions on the VMA allow for the fault which
   346		 * occurred.
   347		 */
   348		if (!(vma->vm_flags & vm_flags)) {
   349			fault = VM_FAULT_BADACCESS;
   350			goto out;
   351		}
   352	
   353		return handle_mm_fault(vma, addr & PAGE_MASK, mm_flags);
   354	
   355	check_stack:
   356		if (vma->vm_flags & VM_GROWSDOWN && !expand_stack(vma, addr))
   357			goto good_area;
   358	out:
   359		return fault;
   360	}
   361	
   362	static bool is_el0_instruction_abort(unsigned int esr)
   363	{
   364		return ESR_ELx_EC(esr) == ESR_ELx_EC_IABT_LOW;
   365	}
   366	
   367	static int __kprobes do_page_fault(unsigned long addr, unsigned int esr,
   368					   struct pt_regs *regs)
   369	{
   370		struct task_struct *tsk;
   371		struct mm_struct *mm;
   372		struct siginfo si;
   373		int fault, major = 0;
   374		unsigned long vm_flags = VM_READ | VM_WRITE;
   375		unsigned int mm_flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE;
   376		struct vm_area_struct *vma;
   377	
   378		if (notify_page_fault(regs, esr))
   379			return 0;
   380	
   381		tsk = current;
   382		mm  = tsk->mm;
   383	
   384		/*
   385		 * If we're in an interrupt or have no user context, we must not take
   386		 * the fault.
   387		 */
   388		if (faulthandler_disabled() || !mm)
   389			goto no_context;
   390	
   391		if (user_mode(regs))
   392			mm_flags |= FAULT_FLAG_USER;
   393	
   394		if (is_el0_instruction_abort(esr)) {
   395			vm_flags = VM_EXEC;
   396		} else if ((esr & ESR_ELx_WNR) && !(esr & ESR_ELx_CM)) {
   397			vm_flags = VM_WRITE;
   398			mm_flags |= FAULT_FLAG_WRITE;
   399		}
   400	
   401		if (addr < TASK_SIZE && is_permission_fault(esr, regs, addr)) {
   402			/* regs->orig_addr_limit may be 0 if we entered from EL0 */
   403			if (regs->orig_addr_limit == KERNEL_DS)
   404				die("Accessing user space memory with fs=KERNEL_DS", regs, esr);
   405	
   406			if (is_el1_instruction_abort(esr))
   407				die("Attempting to execute userspace memory", regs, esr);
   408	
   409			if (!search_exception_tables(regs->pc))
   410				die("Accessing user space memory outside uaccess.h routines", regs, esr);
   411		}
   412	
   413		perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, regs, addr);
   414	
   415		if (IS_ENABLED(CONFIG_SPECULATIVE_PAGE_FAULT)) {
 > 416			fault = handle_speculative_fault(mm, addr, mm_flags, &vma);
   417			/*
   418			 * Page fault is done if VM_FAULT_RETRY is not returned.
   419			 * But if the memory protection keys are active, we don't know
   420			 * if the fault is due to key mistmatch or due to a
   421			 * classic protection check.
   422			 * To differentiate that, we will need the VMA we no
   423			 * more have, so let's retry with the mmap_sem held.
   424			 */
   425			if (fault != VM_FAULT_RETRY &&
   426				 fault != VM_FAULT_SIGSEGV) {
 > 427				perf_sw_event(PERF_COUNT_SW_SPF, 1, regs, addr);
   428				goto done;
   429			}
   430		} else {
   431			vma = NULL;
   432		}
   433	
   434		/*
   435		 * As per x86, we may deadlock here. However, since the kernel only
   436		 * validly references user space from well defined areas of the code,
   437		 * we can bug out early if this is from code which shouldn't.
   438		 */
   439		if (!down_read_trylock(&mm->mmap_sem)) {
   440			if (!user_mode(regs) && !search_exception_tables(regs->pc))
   441				goto no_context;
   442	retry:
   443			down_read(&mm->mmap_sem);
   444		} else {
   445			/*
   446			 * The above down_read_trylock() might have succeeded in which
   447			 * case, we'll have missed the might_sleep() from down_read().
   448			 */
   449			might_sleep();
   450	#ifdef CONFIG_DEBUG_VM
   451			if (!user_mode(regs) && !search_exception_tables(regs->pc))
   452				goto no_context;
   453	#endif
   454		}
   455	
   456		fault = __do_page_fault(mm, addr, mm_flags, vm_flags, tsk, vma);
   457		major |= fault & VM_FAULT_MAJOR;
   458	
   459		if (fault & VM_FAULT_RETRY) {
   460			/*
   461			 * If we need to retry but a fatal signal is pending,
   462			 * handle the signal first. We do not need to release
   463			 * the mmap_sem because it would already be released
   464			 * in __lock_page_or_retry in mm/filemap.c.
   465			 */
   466			if (fatal_signal_pending(current)) {
   467				if (!user_mode(regs))
   468					goto no_context;
   469				return 0;
   470			}
   471	
   472			/*
   473			 * Clear FAULT_FLAG_ALLOW_RETRY to avoid any risk of
   474			 * starvation.
   475			 */
   476			if (mm_flags & FAULT_FLAG_ALLOW_RETRY) {
   477				mm_flags &= ~FAULT_FLAG_ALLOW_RETRY;
   478				mm_flags |= FAULT_FLAG_TRIED;
   479	
   480				/*
   481				 * Do not try to reuse this vma and fetch it
   482				 * again since we will release the mmap_sem.
   483				 */
   484				if (IS_ENABLED(CONFIG_SPECULATIVE_PAGE_FAULT))
   485					vma = NULL;
   486	
   487				goto retry;
   488			}
   489		}
   490		up_read(&mm->mmap_sem);
   491	
   492	done:
   493	
   494		/*
   495		 * Handle the "normal" (no error) case first.
   496		 */
   497		if (likely(!(fault & (VM_FAULT_ERROR | VM_FAULT_BADMAP |
   498				      VM_FAULT_BADACCESS)))) {
   499			/*
   500			 * Major/minor page fault accounting is only done
   501			 * once. If we go through a retry, it is extremely
   502			 * likely that the page will be found in page cache at
   503			 * that point.
   504			 */
   505			if (major) {
   506				tsk->maj_flt++;
   507				perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MAJ, 1, regs,
   508					      addr);
   509			} else {
   510				tsk->min_flt++;
   511				perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MIN, 1, regs,
   512					      addr);
   513			}
   514	
   515			return 0;
   516		}
   517	
   518		/*
   519		 * If we are in kernel mode at this point, we have no context to
   520		 * handle this fault with.
   521		 */
   522		if (!user_mode(regs))
   523			goto no_context;
   524	
   525		if (fault & VM_FAULT_OOM) {
   526			/*
   527			 * We ran out of memory, call the OOM killer, and return to
   528			 * userspace (which will retry the fault, or kill us if we got
   529			 * oom-killed).
   530			 */
   531			pagefault_out_of_memory();
   532			return 0;
   533		}
   534	
   535		clear_siginfo(&si);
   536		si.si_addr = (void __user *)addr;
   537	
   538		if (fault & VM_FAULT_SIGBUS) {
   539			/*
   540			 * We had some memory, but were unable to successfully fix up
   541			 * this page fault.
   542			 */
   543			si.si_signo	= SIGBUS;
   544			si.si_code	= BUS_ADRERR;
   545		} else if (fault & VM_FAULT_HWPOISON_LARGE) {
   546			unsigned int hindex = VM_FAULT_GET_HINDEX(fault);
   547	
   548			si.si_signo	= SIGBUS;
   549			si.si_code	= BUS_MCEERR_AR;
   550			si.si_addr_lsb	= hstate_index_to_shift(hindex);
   551		} else if (fault & VM_FAULT_HWPOISON) {
   552			si.si_signo	= SIGBUS;
   553			si.si_code	= BUS_MCEERR_AR;
   554			si.si_addr_lsb	= PAGE_SHIFT;
   555		} else {
   556			/*
   557			 * Something tried to access memory that isn't in our memory
   558			 * map.
   559			 */
   560			si.si_signo	= SIGSEGV;
   561			si.si_code	= fault == VM_FAULT_BADACCESS ?
   562					  SEGV_ACCERR : SEGV_MAPERR;
   563		}
   564	
   565		__do_user_fault(&si, esr);
   566		return 0;
   567	
   568	no_context:
   569		__do_kernel_fault(addr, esr, regs);
   570		return 0;
   571	}
   572	

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation
-------------- next part --------------
A non-text attachment was scrubbed...
Name: .config.gz
Type: application/gzip
Size: 37763 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20180502/acdff24e/attachment-0001.gz>


More information about the linux-arm-kernel mailing list