diff options
author | Heiko Carstens <heiko.carstens@de.ibm.com> | 2011-05-26 03:48:30 -0400 |
---|---|---|
committer | Heiko Carstens <heiko.carstens@de.ibm.com> | 2011-05-26 03:48:25 -0400 |
commit | 33ce614029576b8585e271fd7d90746a37114a15 (patch) | |
tree | 04f6a764b0ed82f0d6d0647b64547ad24d19830b /arch/s390 | |
parent | 99583181cbf2252dd0554eef6f419a6b22cd33ea (diff) |
[S390] mm: add page fault retry handling
s390 arch backend for d065bd81 "mm: retry page fault when blocking on
disk transfer".
Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>
Diffstat (limited to 'arch/s390')
-rw-r--r-- | arch/s390/mm/fault.c | 41 |
1 files changed, 28 insertions, 13 deletions
diff --git a/arch/s390/mm/fault.c b/arch/s390/mm/fault.c index b57723aee848..fe103e891e7a 100644 --- a/arch/s390/mm/fault.c +++ b/arch/s390/mm/fault.c | |||
@@ -280,7 +280,8 @@ static inline int do_exception(struct pt_regs *regs, int access, | |||
280 | struct mm_struct *mm; | 280 | struct mm_struct *mm; |
281 | struct vm_area_struct *vma; | 281 | struct vm_area_struct *vma; |
282 | unsigned long address; | 282 | unsigned long address; |
283 | int fault, write; | 283 | unsigned int flags; |
284 | int fault; | ||
284 | 285 | ||
285 | if (notify_page_fault(regs)) | 286 | if (notify_page_fault(regs)) |
286 | return 0; | 287 | return 0; |
@@ -299,6 +300,10 @@ static inline int do_exception(struct pt_regs *regs, int access, | |||
299 | 300 | ||
300 | address = trans_exc_code & __FAIL_ADDR_MASK; | 301 | address = trans_exc_code & __FAIL_ADDR_MASK; |
301 | perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, 0, regs, address); | 302 | perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, 0, regs, address); |
303 | flags = FAULT_FLAG_ALLOW_RETRY; | ||
304 | if (access == VM_WRITE || (trans_exc_code & store_indication) == 0x400) | ||
305 | flags |= FAULT_FLAG_WRITE; | ||
306 | retry: | ||
302 | down_read(&mm->mmap_sem); | 307 | down_read(&mm->mmap_sem); |
303 | 308 | ||
304 | fault = VM_FAULT_BADMAP; | 309 | fault = VM_FAULT_BADMAP; |
@@ -328,21 +333,31 @@ static inline int do_exception(struct pt_regs *regs, int access, | |||
328 | * make sure we exit gracefully rather than endlessly redo | 333 | * make sure we exit gracefully rather than endlessly redo |
329 | * the fault. | 334 | * the fault. |
330 | */ | 335 | */ |
331 | write = (access == VM_WRITE || | 336 | fault = handle_mm_fault(mm, vma, address, flags); |
332 | (trans_exc_code & store_indication) == 0x400) ? | ||
333 | FAULT_FLAG_WRITE : 0; | ||
334 | fault = handle_mm_fault(mm, vma, address, write); | ||
335 | if (unlikely(fault & VM_FAULT_ERROR)) | 337 | if (unlikely(fault & VM_FAULT_ERROR)) |
336 | goto out_up; | 338 | goto out_up; |
337 | 339 | ||
338 | if (fault & VM_FAULT_MAJOR) { | 340 | /* |
339 | tsk->maj_flt++; | 341 | * Major/minor page fault accounting is only done on the |
340 | perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MAJ, 1, 0, | 342 | * initial attempt. If we go through a retry, it is extremely |
341 | regs, address); | 343 | * likely that the page will be found in page cache at that point. |
342 | } else { | 344 | */ |
343 | tsk->min_flt++; | 345 | if (flags & FAULT_FLAG_ALLOW_RETRY) { |
344 | perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MIN, 1, 0, | 346 | if (fault & VM_FAULT_MAJOR) { |
345 | regs, address); | 347 | tsk->maj_flt++; |
348 | perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MAJ, 1, 0, | ||
349 | regs, address); | ||
350 | } else { | ||
351 | tsk->min_flt++; | ||
352 | perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MIN, 1, 0, | ||
353 | regs, address); | ||
354 | } | ||
355 | if (fault & VM_FAULT_RETRY) { | ||
356 | /* Clear FAULT_FLAG_ALLOW_RETRY to avoid any risk | ||
357 | * of starvation. */ | ||
358 | flags &= ~FAULT_FLAG_ALLOW_RETRY; | ||
359 | goto retry; | ||
360 | } | ||
346 | } | 361 | } |
347 | /* | 362 | /* |
348 | * The instruction that caused the program check will | 363 | * The instruction that caused the program check will |