aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorPavel Emelyanov <xemul@parallels.com>2013-07-03 18:01:20 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2013-07-03 19:07:26 -0400
commit0f8975ec4db2c8b5bd111b211292ca9be0feb6b8 (patch)
tree47bb0acc9fc3e783ad9cf33097a6636190f5e42b /arch
parent2b0a9f017548f05e42fbf7e67c4a626c1ebd5e12 (diff)
mm: soft-dirty bits for user memory changes tracking
The soft-dirty is a bit on a PTE which helps to track which pages a task writes to. In order to do this tracking one should 1. Clear soft-dirty bits from PTEs ("echo 4 > /proc/PID/clear_refs) 2. Wait some time. 3. Read soft-dirty bits (55'th in /proc/PID/pagemap2 entries) To do this tracking, the writable bit is cleared from PTEs when the soft-dirty bit is. Thus, after this, when the task tries to modify a page at some virtual address the #PF occurs and the kernel sets the soft-dirty bit on the respective PTE. Note, that although all the task's address space is marked as r/o after the soft-dirty bits clear, the #PF-s that occur after that are processed fast. This is so, since the pages are still mapped to physical memory, and thus all the kernel does is finds this fact out and puts back writable, dirty and soft-dirty bits on the PTE. Another thing to note, is that when mremap moves PTEs they are marked with soft-dirty as well, since from the user perspective mremap modifies the virtual memory at mremap's new address. Signed-off-by: Pavel Emelyanov <xemul@parallels.com> Cc: Matt Mackall <mpm@selenic.com> Cc: Xiao Guangrong <xiaoguangrong@linux.vnet.ibm.com> Cc: Glauber Costa <glommer@parallels.com> Cc: Marcelo Tosatti <mtosatti@redhat.com> Cc: KOSAKI Motohiro <kosaki.motohiro@gmail.com> Cc: Stephen Rothwell <sfr@canb.auug.org.au> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'arch')
-rw-r--r--arch/Kconfig3
-rw-r--r--arch/x86/Kconfig1
-rw-r--r--arch/x86/include/asm/pgtable.h24
-rw-r--r--arch/x86/include/asm/pgtable_types.h12
4 files changed, 38 insertions, 2 deletions
diff --git a/arch/Kconfig b/arch/Kconfig
index a4429bcd609e..8d2ae24b9f4a 100644
--- a/arch/Kconfig
+++ b/arch/Kconfig
@@ -365,6 +365,9 @@ config HAVE_IRQ_TIME_ACCOUNTING
365config HAVE_ARCH_TRANSPARENT_HUGEPAGE 365config HAVE_ARCH_TRANSPARENT_HUGEPAGE
366 bool 366 bool
367 367
368config HAVE_ARCH_SOFT_DIRTY
369 bool
370
368config HAVE_MOD_ARCH_SPECIFIC 371config HAVE_MOD_ARCH_SPECIFIC
369 bool 372 bool
370 help 373 help
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index b094816a7e0f..10764a3d62cc 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -102,6 +102,7 @@ config X86
102 select HAVE_ARCH_SECCOMP_FILTER 102 select HAVE_ARCH_SECCOMP_FILTER
103 select BUILDTIME_EXTABLE_SORT 103 select BUILDTIME_EXTABLE_SORT
104 select GENERIC_CMOS_UPDATE 104 select GENERIC_CMOS_UPDATE
105 select HAVE_ARCH_SOFT_DIRTY
105 select CLOCKSOURCE_WATCHDOG 106 select CLOCKSOURCE_WATCHDOG
106 select GENERIC_CLOCKEVENTS 107 select GENERIC_CLOCKEVENTS
107 select ARCH_CLOCKSOURCE_DATA if X86_64 108 select ARCH_CLOCKSOURCE_DATA if X86_64
diff --git a/arch/x86/include/asm/pgtable.h b/arch/x86/include/asm/pgtable.h
index 5b0818bc8963..7dc305a46058 100644
--- a/arch/x86/include/asm/pgtable.h
+++ b/arch/x86/include/asm/pgtable.h
@@ -207,7 +207,7 @@ static inline pte_t pte_mkexec(pte_t pte)
207 207
208static inline pte_t pte_mkdirty(pte_t pte) 208static inline pte_t pte_mkdirty(pte_t pte)
209{ 209{
210 return pte_set_flags(pte, _PAGE_DIRTY); 210 return pte_set_flags(pte, _PAGE_DIRTY | _PAGE_SOFT_DIRTY);
211} 211}
212 212
213static inline pte_t pte_mkyoung(pte_t pte) 213static inline pte_t pte_mkyoung(pte_t pte)
@@ -271,7 +271,7 @@ static inline pmd_t pmd_wrprotect(pmd_t pmd)
271 271
272static inline pmd_t pmd_mkdirty(pmd_t pmd) 272static inline pmd_t pmd_mkdirty(pmd_t pmd)
273{ 273{
274 return pmd_set_flags(pmd, _PAGE_DIRTY); 274 return pmd_set_flags(pmd, _PAGE_DIRTY | _PAGE_SOFT_DIRTY);
275} 275}
276 276
277static inline pmd_t pmd_mkhuge(pmd_t pmd) 277static inline pmd_t pmd_mkhuge(pmd_t pmd)
@@ -294,6 +294,26 @@ static inline pmd_t pmd_mknotpresent(pmd_t pmd)
294 return pmd_clear_flags(pmd, _PAGE_PRESENT); 294 return pmd_clear_flags(pmd, _PAGE_PRESENT);
295} 295}
296 296
297static inline int pte_soft_dirty(pte_t pte)
298{
299 return pte_flags(pte) & _PAGE_SOFT_DIRTY;
300}
301
302static inline int pmd_soft_dirty(pmd_t pmd)
303{
304 return pmd_flags(pmd) & _PAGE_SOFT_DIRTY;
305}
306
307static inline pte_t pte_mksoft_dirty(pte_t pte)
308{
309 return pte_set_flags(pte, _PAGE_SOFT_DIRTY);
310}
311
312static inline pmd_t pmd_mksoft_dirty(pmd_t pmd)
313{
314 return pmd_set_flags(pmd, _PAGE_SOFT_DIRTY);
315}
316
297/* 317/*
298 * Mask out unsupported bits in a present pgprot. Non-present pgprots 318 * Mask out unsupported bits in a present pgprot. Non-present pgprots
299 * can use those bits for other purposes, so leave them be. 319 * 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 e6423002c10b..c98ac63aae48 100644
--- a/arch/x86/include/asm/pgtable_types.h
+++ b/arch/x86/include/asm/pgtable_types.h
@@ -55,6 +55,18 @@
55#define _PAGE_HIDDEN (_AT(pteval_t, 0)) 55#define _PAGE_HIDDEN (_AT(pteval_t, 0))
56#endif 56#endif
57 57
58/*
59 * The same hidden bit is used by kmemcheck, but since kmemcheck
60 * works on kernel pages while soft-dirty engine on user space,
61 * they do not conflict with each other.
62 */
63
64#ifdef CONFIG_MEM_SOFT_DIRTY
65#define _PAGE_SOFT_DIRTY (_AT(pteval_t, 1) << _PAGE_BIT_HIDDEN)
66#else
67#define _PAGE_SOFT_DIRTY (_AT(pteval_t, 0))
68#endif
69
58#if defined(CONFIG_X86_64) || defined(CONFIG_X86_PAE) 70#if defined(CONFIG_X86_64) || defined(CONFIG_X86_PAE)
59#define _PAGE_NX (_AT(pteval_t, 1) << _PAGE_BIT_NX) 71#define _PAGE_NX (_AT(pteval_t, 1) << _PAGE_BIT_NX)
60#else 72#else