diff options
author | Cyrill Gorcunov <gorcunov@gmail.com> | 2013-08-13 19:00:49 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-08-13 20:57:47 -0400 |
commit | 179ef71cbc085252e3fe6b8159263a7ed1d88ea4 (patch) | |
tree | 423b58912b0bf0dc9697fff3d2205b8ca653968e /mm/memory.c | |
parent | 3e6b11df245180949938734bc192eaf32f3a06b3 (diff) |
mm: save soft-dirty bits on swapped pages
Andy Lutomirski reported that if a page with _PAGE_SOFT_DIRTY bit set
get swapped out, the bit is getting lost and no longer available when
pte read back.
To resolve this we introduce _PTE_SWP_SOFT_DIRTY bit which is saved in
pte entry for the page being swapped out. When such page is to be read
back from a swap cache we check for bit presence and if it's there we
clear it and restore the former _PAGE_SOFT_DIRTY bit back.
One of the problem was to find a place in pte entry where we can save
the _PTE_SWP_SOFT_DIRTY bit while page is in swap. The _PAGE_PSE was
chosen for that, it doesn't intersect with swap entry format stored in
pte.
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>
Reviewed-by: Minchan Kim <minchan@kernel.org>
Reviewed-by: 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>
Diffstat (limited to 'mm/memory.c')
-rw-r--r-- | mm/memory.c | 2 |
1 files changed, 2 insertions, 0 deletions
diff --git a/mm/memory.c b/mm/memory.c index 1ce2e2a734fc..e98ecad2b9c8 100644 --- a/mm/memory.c +++ b/mm/memory.c | |||
@@ -3115,6 +3115,8 @@ static int do_swap_page(struct mm_struct *mm, struct vm_area_struct *vma, | |||
3115 | exclusive = 1; | 3115 | exclusive = 1; |
3116 | } | 3116 | } |
3117 | flush_icache_page(vma, page); | 3117 | flush_icache_page(vma, page); |
3118 | if (pte_swp_soft_dirty(orig_pte)) | ||
3119 | pte = pte_mksoft_dirty(pte); | ||
3118 | set_pte_at(mm, address, page_table, pte); | 3120 | set_pte_at(mm, address, page_table, pte); |
3119 | if (page == swapcache) | 3121 | if (page == swapcache) |
3120 | do_page_add_anon_rmap(page, vma, address, exclusive); | 3122 | do_page_add_anon_rmap(page, vma, address, exclusive); |