Skip to content

Commit

Permalink
readahead: fault retry breaks mmap file read random detection
Browse files Browse the repository at this point in the history
.fault now can retry.  The retry can break state machine of .fault.  In
filemap_fault, if page is miss, ra->mmap_miss is increased.  In the second
try, since the page is in page cache now, ra->mmap_miss is decreased.  And
these are done in one fault, so we can't detect random mmap file access.

Add a new flag to indicate .fault is tried once.  In the second try, skip
ra->mmap_miss decreasing.  The filemap_fault state machine is ok with it.

I only tested x86, didn't test other archs, but looks the change for other
archs is obvious, but who knows :)

Signed-off-by: Shaohua Li <[email protected]>
Cc: Rik van Riel <[email protected]>
Cc: Wu Fengguang <[email protected]>
Signed-off-by: Andrew Morton <[email protected]>
Signed-off-by: Linus Torvalds <[email protected]>
  • Loading branch information
Shaohua Li authored and torvalds committed Oct 9, 2012
1 parent e79bee2 commit 45cac65
Show file tree
Hide file tree
Showing 20 changed files with 21 additions and 2 deletions.
1 change: 1 addition & 0 deletions arch/arm/mm/fault.c
Original file line number Diff line number Diff line change
Expand Up @@ -336,6 +336,7 @@ do_page_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
/* Clear FAULT_FLAG_ALLOW_RETRY to avoid any risk
* of starvation. */
flags &= ~FAULT_FLAG_ALLOW_RETRY;
flags |= FAULT_FLAG_TRIED;
goto retry;
}
}
Expand Down
1 change: 1 addition & 0 deletions arch/avr32/mm/fault.c
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,7 @@ asmlinkage void do_page_fault(unsigned long ecr, struct pt_regs *regs)
tsk->min_flt++;
if (fault & VM_FAULT_RETRY) {
flags &= ~FAULT_FLAG_ALLOW_RETRY;
flags |= FAULT_FLAG_TRIED;

/*
* No need to up_read(&mm->mmap_sem) as we would have
Expand Down
1 change: 1 addition & 0 deletions arch/cris/mm/fault.c
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,7 @@ do_page_fault(unsigned long address, struct pt_regs *regs,
tsk->min_flt++;
if (fault & VM_FAULT_RETRY) {
flags &= ~FAULT_FLAG_ALLOW_RETRY;
flags |= FAULT_FLAG_TRIED;

/*
* No need to up_read(&mm->mmap_sem) as we would
Expand Down
1 change: 1 addition & 0 deletions arch/hexagon/mm/vm_fault.c
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ void do_page_fault(unsigned long address, long cause, struct pt_regs *regs)
current->min_flt++;
if (fault & VM_FAULT_RETRY) {
flags &= ~FAULT_FLAG_ALLOW_RETRY;
flags |= FAULT_FLAG_TRIED;
goto retry;
}
}
Expand Down
1 change: 1 addition & 0 deletions arch/ia64/mm/fault.c
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,7 @@ ia64_do_page_fault (unsigned long address, unsigned long isr, struct pt_regs *re
current->min_flt++;
if (fault & VM_FAULT_RETRY) {
flags &= ~FAULT_FLAG_ALLOW_RETRY;
flags |= FAULT_FLAG_TRIED;

/* No need to up_read(&mm->mmap_sem) as we would
* have already released it in __lock_page_or_retry
Expand Down
1 change: 1 addition & 0 deletions arch/m68k/mm/fault.c
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,7 @@ int do_page_fault(struct pt_regs *regs, unsigned long address,
/* Clear FAULT_FLAG_ALLOW_RETRY to avoid any risk
* of starvation. */
flags &= ~FAULT_FLAG_ALLOW_RETRY;
flags |= FAULT_FLAG_TRIED;

/*
* No need to up_read(&mm->mmap_sem) as we would
Expand Down
1 change: 1 addition & 0 deletions arch/microblaze/mm/fault.c
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,7 @@ void do_page_fault(struct pt_regs *regs, unsigned long address,
current->min_flt++;
if (fault & VM_FAULT_RETRY) {
flags &= ~FAULT_FLAG_ALLOW_RETRY;
flags |= FAULT_FLAG_TRIED;

/*
* No need to up_read(&mm->mmap_sem) as we would
Expand Down
1 change: 1 addition & 0 deletions arch/mips/mm/fault.c
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,7 @@ asmlinkage void __kprobes do_page_fault(struct pt_regs *regs, unsigned long writ
}
if (fault & VM_FAULT_RETRY) {
flags &= ~FAULT_FLAG_ALLOW_RETRY;
flags |= FAULT_FLAG_TRIED;

/*
* No need to up_read(&mm->mmap_sem) as we would
Expand Down
1 change: 1 addition & 0 deletions arch/openrisc/mm/fault.c
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,7 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long address,
tsk->min_flt++;
if (fault & VM_FAULT_RETRY) {
flags &= ~FAULT_FLAG_ALLOW_RETRY;
flags |= FAULT_FLAG_TRIED;

/* No need to up_read(&mm->mmap_sem) as we would
* have already released it in __lock_page_or_retry
Expand Down
1 change: 1 addition & 0 deletions arch/powerpc/mm/fault.c
Original file line number Diff line number Diff line change
Expand Up @@ -451,6 +451,7 @@ int __kprobes do_page_fault(struct pt_regs *regs, unsigned long address,
/* Clear FAULT_FLAG_ALLOW_RETRY to avoid any risk
* of starvation. */
flags &= ~FAULT_FLAG_ALLOW_RETRY;
flags |= FAULT_FLAG_TRIED;
goto retry;
}
}
Expand Down
1 change: 1 addition & 0 deletions arch/s390/mm/fault.c
Original file line number Diff line number Diff line change
Expand Up @@ -367,6 +367,7 @@ static inline int do_exception(struct pt_regs *regs, int access)
/* Clear FAULT_FLAG_ALLOW_RETRY to avoid any risk
* of starvation. */
flags &= ~FAULT_FLAG_ALLOW_RETRY;
flags |= FAULT_FLAG_TRIED;
down_read(&mm->mmap_sem);
goto retry;
}
Expand Down
1 change: 1 addition & 0 deletions arch/sh/mm/fault.c
Original file line number Diff line number Diff line change
Expand Up @@ -504,6 +504,7 @@ asmlinkage void __kprobes do_page_fault(struct pt_regs *regs,
}
if (fault & VM_FAULT_RETRY) {
flags &= ~FAULT_FLAG_ALLOW_RETRY;
flags |= FAULT_FLAG_TRIED;

/*
* No need to up_read(&mm->mmap_sem) as we would
Expand Down
1 change: 1 addition & 0 deletions arch/sparc/mm/fault_32.c
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,7 @@ asmlinkage void do_sparc_fault(struct pt_regs *regs, int text_fault, int write,
}
if (fault & VM_FAULT_RETRY) {
flags &= ~FAULT_FLAG_ALLOW_RETRY;
flags |= FAULT_FLAG_TRIED;

/* No need to up_read(&mm->mmap_sem) as we would
* have already released it in __lock_page_or_retry
Expand Down
1 change: 1 addition & 0 deletions arch/sparc/mm/fault_64.c
Original file line number Diff line number Diff line change
Expand Up @@ -452,6 +452,7 @@ asmlinkage void __kprobes do_sparc64_fault(struct pt_regs *regs)
}
if (fault & VM_FAULT_RETRY) {
flags &= ~FAULT_FLAG_ALLOW_RETRY;
flags |= FAULT_FLAG_TRIED;

/* No need to up_read(&mm->mmap_sem) as we would
* have already released it in __lock_page_or_retry
Expand Down
1 change: 1 addition & 0 deletions arch/tile/mm/fault.c
Original file line number Diff line number Diff line change
Expand Up @@ -454,6 +454,7 @@ static int handle_page_fault(struct pt_regs *regs,
tsk->min_flt++;
if (fault & VM_FAULT_RETRY) {
flags &= ~FAULT_FLAG_ALLOW_RETRY;
flags |= FAULT_FLAG_TRIED;

/*
* No need to up_read(&mm->mmap_sem) as we would
Expand Down
1 change: 1 addition & 0 deletions arch/um/kernel/trap.c
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ int handle_page_fault(unsigned long address, unsigned long ip,
current->min_flt++;
if (fault & VM_FAULT_RETRY) {
flags &= ~FAULT_FLAG_ALLOW_RETRY;
flags |= FAULT_FLAG_TRIED;

goto retry;
}
Expand Down
1 change: 1 addition & 0 deletions arch/x86/mm/fault.c
Original file line number Diff line number Diff line change
Expand Up @@ -1220,6 +1220,7 @@ __do_page_fault(struct pt_regs *regs, unsigned long error_code)
/* Clear FAULT_FLAG_ALLOW_RETRY to avoid any risk
* of starvation. */
flags &= ~FAULT_FLAG_ALLOW_RETRY;
flags |= FAULT_FLAG_TRIED;
goto retry;
}
}
Expand Down
1 change: 1 addition & 0 deletions arch/xtensa/mm/fault.c
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ void do_page_fault(struct pt_regs *regs)
current->min_flt++;
if (fault & VM_FAULT_RETRY) {
flags &= ~FAULT_FLAG_ALLOW_RETRY;
flags |= FAULT_FLAG_TRIED;

/* No need to up_read(&mm->mmap_sem) as we would
* have already released it in __lock_page_or_retry
Expand Down
1 change: 1 addition & 0 deletions include/linux/mm.h
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,7 @@ extern pgprot_t protection_map[16];
#define FAULT_FLAG_ALLOW_RETRY 0x08 /* Retry fault if blocking */
#define FAULT_FLAG_RETRY_NOWAIT 0x10 /* Don't drop mmap_sem and wait when retrying */
#define FAULT_FLAG_KILLABLE 0x20 /* The fault task is in SIGKILL killable region */
#define FAULT_FLAG_TRIED 0x40 /* second try */

/*
* vm_fault is filled by the the pagefault handler and passed to the vma's
Expand Down
4 changes: 2 additions & 2 deletions mm/filemap.c
Original file line number Diff line number Diff line change
Expand Up @@ -1607,13 +1607,13 @@ int filemap_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
* Do we have something in the page cache already?
*/
page = find_get_page(mapping, offset);
if (likely(page)) {
if (likely(page) && !(vmf->flags & FAULT_FLAG_TRIED)) {
/*
* We found the page, so try async readahead before
* waiting for the lock.
*/
do_async_mmap_readahead(vma, ra, file, page, offset);
} else {
} else if (!page) {
/* No page in the page cache at all */
do_sync_mmap_readahead(vma, ra, file, offset);
count_vm_event(PGMAJFAULT);
Expand Down

0 comments on commit 45cac65

Please sign in to comment.