diff options
| author | Cyrill Gorcunov <gorcunov@gmail.com> | 2013-08-13 19:00:51 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-08-13 20:57:48 -0400 |
| commit | 41bb3476b361ef38576cf9d539b19bae2ac93167 (patch) | |
| tree | 907f72f0cc27762a9cb9c2857fe6c360524112f9 | |
| parent | 179ef71cbc085252e3fe6b8159263a7ed1d88ea4 (diff) | |
mm: save soft-dirty bits on file pages
Andy reported that if file page get reclaimed we lose the soft-dirty bit
if it was there, so save _PAGE_BIT_SOFT_DIRTY bit when page address get
encoded into pte entry. Thus when #pf happens on such non-present pte
we can restore it back.
Reported-by: Andy Lutomirski <luto@amacapital.net>
Signed-off-by: Cyrill Gorcunov <gorcunov@openvz.org>
Acked-by: Pavel Emelyanov <xemul@parallels.com>
Cc: Matt Mackall <mpm@selenic.com>
Cc: Xiao Guangrong <xiaoguangrong@linux.vnet.ibm.com>
Cc: Marcelo Tosatti <mtosatti@redhat.com>
Cc: KOSAKI Motohiro <kosaki.motohiro@gmail.com>
Cc: Stephen Rothwell <sfr@canb.auug.org.au>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: "Aneesh Kumar K.V" <aneesh.kumar@linux.vnet.ibm.com>
Cc: Minchan Kim <minchan@kernel.org>
Cc: Wanpeng Li <liwanp@linux.vnet.ibm.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
| -rw-r--r-- | arch/x86/include/asm/pgtable-2level.h | 48 | ||||
| -rw-r--r-- | arch/x86/include/asm/pgtable-3level.h | 3 | ||||
| -rw-r--r-- | arch/x86/include/asm/pgtable.h | 15 | ||||
| -rw-r--r-- | arch/x86/include/asm/pgtable_types.h | 4 | ||||
| -rw-r--r-- | fs/proc/task_mmu.c | 2 | ||||
| -rw-r--r-- | include/asm-generic/pgtable.h | 15 | ||||
| -rw-r--r-- | mm/fremap.c | 11 | ||||
| -rw-r--r-- | mm/memory.c | 11 | ||||
| -rw-r--r-- | mm/rmap.c | 8 |
9 files changed, 107 insertions, 10 deletions
diff --git a/arch/x86/include/asm/pgtable-2level.h b/arch/x86/include/asm/pgtable-2level.h index f2b489cf1602..3bf2dd0cf61f 100644 --- a/arch/x86/include/asm/pgtable-2level.h +++ b/arch/x86/include/asm/pgtable-2level.h | |||
| @@ -55,9 +55,53 @@ static inline pmd_t native_pmdp_get_and_clear(pmd_t *xp) | |||
| 55 | #define native_pmdp_get_and_clear(xp) native_local_pmdp_get_and_clear(xp) | 55 | #define native_pmdp_get_and_clear(xp) native_local_pmdp_get_and_clear(xp) |
| 56 | #endif | 56 | #endif |
| 57 | 57 | ||
| 58 | #ifdef CONFIG_MEM_SOFT_DIRTY | ||
| 59 | |||
| 60 | /* | ||
| 61 | * Bits _PAGE_BIT_PRESENT, _PAGE_BIT_FILE, _PAGE_BIT_SOFT_DIRTY and | ||
| 62 | * _PAGE_BIT_PROTNONE are taken, split up the 28 bits of offset | ||
| 63 | * into this range. | ||
| 64 | */ | ||
| 65 | #define PTE_FILE_MAX_BITS 28 | ||
| 66 | #define PTE_FILE_SHIFT1 (_PAGE_BIT_PRESENT + 1) | ||
| 67 | #define PTE_FILE_SHIFT2 (_PAGE_BIT_FILE + 1) | ||
| 68 | #define PTE_FILE_SHIFT3 (_PAGE_BIT_PROTNONE + 1) | ||
| 69 | #define PTE_FILE_SHIFT4 (_PAGE_BIT_SOFT_DIRTY + 1) | ||
| 70 | #define PTE_FILE_BITS1 (PTE_FILE_SHIFT2 - PTE_FILE_SHIFT1 - 1) | ||
| 71 | #define PTE_FILE_BITS2 (PTE_FILE_SHIFT3 - PTE_FILE_SHIFT2 - 1) | ||
| 72 | #define PTE_FILE_BITS3 (PTE_FILE_SHIFT4 - PTE_FILE_SHIFT3 - 1) | ||
| 73 | |||
| 74 | #define pte_to_pgoff(pte) \ | ||
| 75 | ((((pte).pte_low >> (PTE_FILE_SHIFT1)) \ | ||
| 76 | & ((1U << PTE_FILE_BITS1) - 1))) \ | ||
| 77 | + ((((pte).pte_low >> (PTE_FILE_SHIFT2)) \ | ||
| 78 | & ((1U << PTE_FILE_BITS2) - 1)) \ | ||
| 79 | << (PTE_FILE_BITS1)) \ | ||
| 80 | + ((((pte).pte_low >> (PTE_FILE_SHIFT3)) \ | ||
| 81 | & ((1U << PTE_FILE_BITS3) - 1)) \ | ||
| 82 | << (PTE_FILE_BITS1 + PTE_FILE_BITS2)) \ | ||
| 83 | + ((((pte).pte_low >> (PTE_FILE_SHIFT4))) \ | ||
| 84 | << (PTE_FILE_BITS1 + PTE_FILE_BITS2 + PTE_FILE_BITS3)) | ||
| 85 | |||
| 86 | #define pgoff_to_pte(off) \ | ||
| 87 | ((pte_t) { .pte_low = \ | ||
| 88 | ((((off)) & ((1U << PTE_FILE_BITS1) - 1)) << PTE_FILE_SHIFT1) \ | ||
| 89 | + ((((off) >> PTE_FILE_BITS1) \ | ||
| 90 | & ((1U << PTE_FILE_BITS2) - 1)) \ | ||
| 91 | << PTE_FILE_SHIFT2) \ | ||
| 92 | + ((((off) >> (PTE_FILE_BITS1 + PTE_FILE_BITS2)) \ | ||
| 93 | & ((1U << PTE_FILE_BITS3) - 1)) \ | ||
| 94 | << PTE_FILE_SHIFT3) \ | ||
| 95 | + ((((off) >> \ | ||
| 96 | (PTE_FILE_BITS1 + PTE_FILE_BITS2 + PTE_FILE_BITS3))) \ | ||
| 97 | << PTE_FILE_SHIFT4) \ | ||
| 98 | + _PAGE_FILE }) | ||
| 99 | |||
| 100 | #else /* CONFIG_MEM_SOFT_DIRTY */ | ||
| 101 | |||
| 58 | /* | 102 | /* |
| 59 | * Bits _PAGE_BIT_PRESENT, _PAGE_BIT_FILE and _PAGE_BIT_PROTNONE are taken, | 103 | * Bits _PAGE_BIT_PRESENT, _PAGE_BIT_FILE and _PAGE_BIT_PROTNONE are taken, |
| 60 | * split up the 29 bits of offset into this range: | 104 | * split up the 29 bits of offset into this range. |
| 61 | */ | 105 | */ |
| 62 | #define PTE_FILE_MAX_BITS 29 | 106 | #define PTE_FILE_MAX_BITS 29 |
| 63 | #define PTE_FILE_SHIFT1 (_PAGE_BIT_PRESENT + 1) | 107 | #define PTE_FILE_SHIFT1 (_PAGE_BIT_PRESENT + 1) |
| @@ -88,6 +132,8 @@ static inline pmd_t native_pmdp_get_and_clear(pmd_t *xp) | |||
| 88 | << PTE_FILE_SHIFT3) \ | 132 | << PTE_FILE_SHIFT3) \ |
| 89 | + _PAGE_FILE }) | 133 | + _PAGE_FILE }) |
| 90 | 134 | ||
| 135 | #endif /* CONFIG_MEM_SOFT_DIRTY */ | ||
| 136 | |||
| 91 | /* Encode and de-code a swap entry */ | 137 | /* Encode and de-code a swap entry */ |
| 92 | #if _PAGE_BIT_FILE < _PAGE_BIT_PROTNONE | 138 | #if _PAGE_BIT_FILE < _PAGE_BIT_PROTNONE |
| 93 | #define SWP_TYPE_BITS (_PAGE_BIT_FILE - _PAGE_BIT_PRESENT - 1) | 139 | #define SWP_TYPE_BITS (_PAGE_BIT_FILE - _PAGE_BIT_PRESENT - 1) |
diff --git a/arch/x86/include/asm/pgtable-3level.h b/arch/x86/include/asm/pgtable-3level.h index 4cc9f2b7cdc3..81bb91b49a88 100644 --- a/arch/x86/include/asm/pgtable-3level.h +++ b/arch/x86/include/asm/pgtable-3level.h | |||
| @@ -179,6 +179,9 @@ static inline pmd_t native_pmdp_get_and_clear(pmd_t *pmdp) | |||
| 179 | /* | 179 | /* |
| 180 | * Bits 0, 6 and 7 are taken in the low part of the pte, | 180 | * Bits 0, 6 and 7 are taken in the low part of the pte, |
| 181 | * put the 32 bits of offset into the high part. | 181 | * put the 32 bits of offset into the high part. |
| 182 | * | ||
| 183 | * For soft-dirty tracking 11 bit is taken from | ||
| 184 | * the low part of pte as well. | ||
| 182 | */ | 185 | */ |
| 183 | #define pte_to_pgoff(pte) ((pte).pte_high) | 186 | #define pte_to_pgoff(pte) ((pte).pte_high) |
| 184 | #define pgoff_to_pte(off) \ | 187 | #define pgoff_to_pte(off) \ |
diff --git a/arch/x86/include/asm/pgtable.h b/arch/x86/include/asm/pgtable.h index bd0518a7f197..1c00631164c2 100644 --- a/arch/x86/include/asm/pgtable.h +++ b/arch/x86/include/asm/pgtable.h | |||
| @@ -329,6 +329,21 @@ static inline pte_t pte_swp_clear_soft_dirty(pte_t pte) | |||
| 329 | return pte_clear_flags(pte, _PAGE_SWP_SOFT_DIRTY); | 329 | return pte_clear_flags(pte, _PAGE_SWP_SOFT_DIRTY); |
| 330 | } | 330 | } |
| 331 | 331 | ||
| 332 | static inline pte_t pte_file_clear_soft_dirty(pte_t pte) | ||
| 333 | { | ||
| 334 | return pte_clear_flags(pte, _PAGE_SOFT_DIRTY); | ||
| 335 | } | ||
| 336 | |||
| 337 | static inline pte_t pte_file_mksoft_dirty(pte_t pte) | ||
| 338 | { | ||
| 339 | return pte_set_flags(pte, _PAGE_SOFT_DIRTY); | ||
| 340 | } | ||
| 341 | |||
| 342 | static inline int pte_file_soft_dirty(pte_t pte) | ||
| 343 | { | ||
| 344 | return pte_flags(pte) & _PAGE_SOFT_DIRTY; | ||
| 345 | } | ||
| 346 | |||
| 332 | /* | 347 | /* |
| 333 | * Mask out unsupported bits in a present pgprot. Non-present pgprots | 348 | * Mask out unsupported bits in a present pgprot. Non-present pgprots |
| 334 | * can use those bits for other purposes, so leave them be. | 349 | * can use those bits for other purposes, so leave them be. |
diff --git a/arch/x86/include/asm/pgtable_types.h b/arch/x86/include/asm/pgtable_types.h index 5e8442f178f9..f4843e031131 100644 --- a/arch/x86/include/asm/pgtable_types.h +++ b/arch/x86/include/asm/pgtable_types.h | |||
| @@ -61,8 +61,10 @@ | |||
| 61 | * they do not conflict with each other. | 61 | * they do not conflict with each other. |
| 62 | */ | 62 | */ |
| 63 | 63 | ||
| 64 | #define _PAGE_BIT_SOFT_DIRTY _PAGE_BIT_HIDDEN | ||
| 65 | |||
| 64 | #ifdef CONFIG_MEM_SOFT_DIRTY | 66 | #ifdef CONFIG_MEM_SOFT_DIRTY |
| 65 | #define _PAGE_SOFT_DIRTY (_AT(pteval_t, 1) << _PAGE_BIT_HIDDEN) | 67 | #define _PAGE_SOFT_DIRTY (_AT(pteval_t, 1) << _PAGE_BIT_SOFT_DIRTY) |
| 66 | #else | 68 | #else |
| 67 | #define _PAGE_SOFT_DIRTY (_AT(pteval_t, 0)) | 69 | #define _PAGE_SOFT_DIRTY (_AT(pteval_t, 0)) |
| 68 | #endif | 70 | #endif |
diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c index e2d9bdce5e7e..a11720767abc 100644 --- a/fs/proc/task_mmu.c +++ b/fs/proc/task_mmu.c | |||
| @@ -736,6 +736,8 @@ static inline void clear_soft_dirty(struct vm_area_struct *vma, | |||
| 736 | ptent = pte_clear_flags(ptent, _PAGE_SOFT_DIRTY); | 736 | ptent = pte_clear_flags(ptent, _PAGE_SOFT_DIRTY); |
| 737 | } else if (is_swap_pte(ptent)) { | 737 | } else if (is_swap_pte(ptent)) { |
| 738 | ptent = pte_swp_clear_soft_dirty(ptent); | 738 | ptent = pte_swp_clear_soft_dirty(ptent); |
| 739 | } else if (pte_file(ptent)) { | ||
| 740 | ptent = pte_file_clear_soft_dirty(ptent); | ||
| 739 | } | 741 | } |
| 740 | 742 | ||
| 741 | set_pte_at(vma->vm_mm, addr, pte, ptent); | 743 | set_pte_at(vma->vm_mm, addr, pte, ptent); |
diff --git a/include/asm-generic/pgtable.h b/include/asm-generic/pgtable.h index 2a7e0d10ad9a..0807ddf97b05 100644 --- a/include/asm-generic/pgtable.h +++ b/include/asm-generic/pgtable.h | |||
| @@ -432,6 +432,21 @@ static inline pte_t pte_swp_clear_soft_dirty(pte_t pte) | |||
| 432 | { | 432 | { |
| 433 | return pte; | 433 | return pte; |
| 434 | } | 434 | } |
| 435 | |||
| 436 | static inline pte_t pte_file_clear_soft_dirty(pte_t pte) | ||
| 437 | { | ||
| 438 | return pte; | ||
| 439 | } | ||
| 440 | |||
| 441 | static inline pte_t pte_file_mksoft_dirty(pte_t pte) | ||
| 442 | { | ||
| 443 | return pte; | ||
| 444 | } | ||
| 445 | |||
| 446 | static inline int pte_file_soft_dirty(pte_t pte) | ||
| 447 | { | ||
| 448 | return 0; | ||
| 449 | } | ||
| 435 | #endif | 450 | #endif |
| 436 | 451 | ||
| 437 | #ifndef __HAVE_PFNMAP_TRACKING | 452 | #ifndef __HAVE_PFNMAP_TRACKING |
diff --git a/mm/fremap.c b/mm/fremap.c index 87da3590c61e..5bff08147768 100644 --- a/mm/fremap.c +++ b/mm/fremap.c | |||
| @@ -57,17 +57,22 @@ static int install_file_pte(struct mm_struct *mm, struct vm_area_struct *vma, | |||
| 57 | unsigned long addr, unsigned long pgoff, pgprot_t prot) | ||
