diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2018-09-13 05:57:48 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2018-09-13 21:18:04 -0400 |
commit | 7a9cdebdcc17e426fb5287e4a82db1dfe86339b2 (patch) | |
tree | de9aa025a0d421ee3ae3d1973e63419fff8545e5 | |
parent | 54eda9df17f3215b9ed16629ee71ea07413efdaf (diff) |
mm: get rid of vmacache_flush_all() entirely
Jann Horn points out that the vmacache_flush_all() function is not only
potentially expensive, it's buggy too. It also happens to be entirely
unnecessary, because the sequence number overflow case can be avoided by
simply making the sequence number be 64-bit. That doesn't even grow the
data structures in question, because the other adjacent fields are
already 64-bit.
So simplify the whole thing by just making the sequence number overflow
case go away entirely, which gets rid of all the complications and makes
the code faster too. Win-win.
[ Oleg Nesterov points out that the VMACACHE_FULL_FLUSHES statistics
also just goes away entirely with this ]
Reported-by: Jann Horn <jannh@google.com>
Suggested-by: Will Deacon <will.deacon@arm.com>
Acked-by: Davidlohr Bueso <dave@stgolabs.net>
Cc: Oleg Nesterov <oleg@redhat.com>
Cc: stable@kernel.org
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r-- | include/linux/mm_types.h | 2 | ||||
-rw-r--r-- | include/linux/mm_types_task.h | 2 | ||||
-rw-r--r-- | include/linux/vm_event_item.h | 1 | ||||
-rw-r--r-- | include/linux/vmacache.h | 5 | ||||
-rw-r--r-- | mm/debug.c | 4 | ||||
-rw-r--r-- | mm/vmacache.c | 38 |
6 files changed, 4 insertions, 48 deletions
diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h index cd2bc939efd0..5ed8f6292a53 100644 --- a/include/linux/mm_types.h +++ b/include/linux/mm_types.h | |||
@@ -341,7 +341,7 @@ struct mm_struct { | |||
341 | struct { | 341 | struct { |
342 | struct vm_area_struct *mmap; /* list of VMAs */ | 342 | struct vm_area_struct *mmap; /* list of VMAs */ |
343 | struct rb_root mm_rb; | 343 | struct rb_root mm_rb; |
344 | u32 vmacache_seqnum; /* per-thread vmacache */ | 344 | u64 vmacache_seqnum; /* per-thread vmacache */ |
345 | #ifdef CONFIG_MMU | 345 | #ifdef CONFIG_MMU |
346 | unsigned long (*get_unmapped_area) (struct file *filp, | 346 | unsigned long (*get_unmapped_area) (struct file *filp, |
347 | unsigned long addr, unsigned long len, | 347 | unsigned long addr, unsigned long len, |
diff --git a/include/linux/mm_types_task.h b/include/linux/mm_types_task.h index 5fe87687664c..d7016dcb245e 100644 --- a/include/linux/mm_types_task.h +++ b/include/linux/mm_types_task.h | |||
@@ -32,7 +32,7 @@ | |||
32 | #define VMACACHE_MASK (VMACACHE_SIZE - 1) | 32 | #define VMACACHE_MASK (VMACACHE_SIZE - 1) |
33 | 33 | ||
34 | struct vmacache { | 34 | struct vmacache { |
35 | u32 seqnum; | 35 | u64 seqnum; |
36 | struct vm_area_struct *vmas[VMACACHE_SIZE]; | 36 | struct vm_area_struct *vmas[VMACACHE_SIZE]; |
37 | }; | 37 | }; |
38 | 38 | ||
diff --git a/include/linux/vm_event_item.h b/include/linux/vm_event_item.h index 5c7f010676a7..47a3441cf4c4 100644 --- a/include/linux/vm_event_item.h +++ b/include/linux/vm_event_item.h | |||
@@ -105,7 +105,6 @@ enum vm_event_item { PGPGIN, PGPGOUT, PSWPIN, PSWPOUT, | |||
105 | #ifdef CONFIG_DEBUG_VM_VMACACHE | 105 | #ifdef CONFIG_DEBUG_VM_VMACACHE |
106 | VMACACHE_FIND_CALLS, | 106 | VMACACHE_FIND_CALLS, |
107 | VMACACHE_FIND_HITS, | 107 | VMACACHE_FIND_HITS, |
108 | VMACACHE_FULL_FLUSHES, | ||
109 | #endif | 108 | #endif |
110 | #ifdef CONFIG_SWAP | 109 | #ifdef CONFIG_SWAP |
111 | SWAP_RA, | 110 | SWAP_RA, |
diff --git a/include/linux/vmacache.h b/include/linux/vmacache.h index 3e9a963edd6a..6fce268a4588 100644 --- a/include/linux/vmacache.h +++ b/include/linux/vmacache.h | |||
@@ -10,7 +10,6 @@ static inline void vmacache_flush(struct task_struct *tsk) | |||
10 | memset(tsk->vmacache.vmas, 0, sizeof(tsk->vmacache.vmas)); | 10 | memset(tsk->vmacache.vmas, 0, sizeof(tsk->vmacache.vmas)); |
11 | } | 11 | } |
12 | 12 | ||
13 | extern void vmacache_flush_all(struct mm_struct *mm); | ||
14 | extern void vmacache_update(unsigned long addr, struct vm_area_struct *newvma); | 13 | extern void vmacache_update(unsigned long addr, struct vm_area_struct *newvma); |
15 | extern struct vm_area_struct *vmacache_find(struct mm_struct *mm, | 14 | extern struct vm_area_struct *vmacache_find(struct mm_struct *mm, |
16 | unsigned long addr); | 15 | unsigned long addr); |
@@ -24,10 +23,6 @@ extern struct vm_area_struct *vmacache_find_exact(struct mm_struct *mm, | |||
24 | static inline void vmacache_invalidate(struct mm_struct *mm) | 23 | static inline void vmacache_invalidate(struct mm_struct *mm) |
25 | { | 24 | { |
26 | mm->vmacache_seqnum++; | 25 | mm->vmacache_seqnum++; |
27 | |||
28 | /* deal with overflows */ | ||
29 | if (unlikely(mm->vmacache_seqnum == 0)) | ||
30 | vmacache_flush_all(mm); | ||
31 | } | 26 | } |
32 | 27 | ||
33 | #endif /* __LINUX_VMACACHE_H */ | 28 | #endif /* __LINUX_VMACACHE_H */ |
diff --git a/mm/debug.c b/mm/debug.c index 38c926520c97..bd10aad8539a 100644 --- a/mm/debug.c +++ b/mm/debug.c | |||
@@ -114,7 +114,7 @@ EXPORT_SYMBOL(dump_vma); | |||
114 | 114 | ||
115 | void dump_mm(const struct mm_struct *mm) | 115 | void dump_mm(const struct mm_struct *mm) |
116 | { | 116 | { |
117 | pr_emerg("mm %px mmap %px seqnum %d task_size %lu\n" | 117 | pr_emerg("mm %px mmap %px seqnum %llu task_size %lu\n" |
118 | #ifdef CONFIG_MMU | 118 | #ifdef CONFIG_MMU |
119 | "get_unmapped_area %px\n" | 119 | "get_unmapped_area %px\n" |
120 | #endif | 120 | #endif |
@@ -142,7 +142,7 @@ void dump_mm(const struct mm_struct *mm) | |||
142 | "tlb_flush_pending %d\n" | 142 | "tlb_flush_pending %d\n" |
143 | "def_flags: %#lx(%pGv)\n", | 143 | "def_flags: %#lx(%pGv)\n", |
144 | 144 | ||
145 | mm, mm->mmap, mm->vmacache_seqnum, mm->task_size, | 145 | mm, mm->mmap, (long long) mm->vmacache_seqnum, mm->task_size, |
146 | #ifdef CONFIG_MMU | 146 | #ifdef CONFIG_MMU |
147 | mm->get_unmapped_area, | 147 | mm->get_unmapped_area, |
148 | #endif | 148 | #endif |
diff --git a/mm/vmacache.c b/mm/vmacache.c index ea517bef7dc5..cdc32a3b02fa 100644 --- a/mm/vmacache.c +++ b/mm/vmacache.c | |||
@@ -20,44 +20,6 @@ | |||
20 | #define VMACACHE_HASH(addr) ((addr >> VMACACHE_SHIFT) & VMACACHE_MASK) | 20 | #define VMACACHE_HASH(addr) ((addr >> VMACACHE_SHIFT) & VMACACHE_MASK) |
21 | 21 | ||
22 | /* | 22 | /* |
23 | * Flush vma caches for threads that share a given mm. | ||
24 | * | ||
25 | * The operation is safe because the caller holds the mmap_sem | ||
26 | * exclusively and other threads accessing the vma cache will | ||
27 | * have mmap_sem held at least for read, so no extra locking | ||
28 | * is required to maintain the vma cache. | ||
29 | */ | ||
30 | void vmacache_flush_all(struct mm_struct *mm) | ||
31 | { | ||
32 | struct task_struct *g, *p; | ||
33 | |||
34 | count_vm_vmacache_event(VMACACHE_FULL_FLUSHES); | ||
35 | |||
36 | /* | ||
37 | * Single threaded tasks need not iterate the entire | ||
38 | * list of process. We can avoid the flushing as well | ||
39 | * since the mm's seqnum was increased and don't have | ||
40 | * to worry about other threads' seqnum. Current's | ||
41 | * flush will occur upon the next lookup. | ||
42 | */ | ||
43 | if (atomic_read(&mm->mm_users) == 1) | ||
44 | return; | ||
45 | |||
46 | rcu_read_lock(); | ||
47 | for_each_process_thread(g, p) { | ||
48 | /* | ||
49 | * Only flush the vmacache pointers as the | ||
50 | * mm seqnum is already set and curr's will | ||
51 | * be set upon invalidation when the next | ||
52 | * lookup is done. | ||
53 | */ | ||
54 | if (mm == p->mm) | ||
55 | vmacache_flush(p); | ||
56 | } | ||
57 | rcu_read_unlock(); | ||
58 | } | ||
59 | |||
60 | /* | ||
61 | * This task may be accessing a foreign mm via (for example) | 23 | * This task may be accessing a foreign mm via (for example) |
62 | * get_user_pages()->find_vma(). The vmacache is task-local and this | 24 | * get_user_pages()->find_vma(). The vmacache is task-local and this |
63 | * task's vmacache pertains to a different mm (ie, its own). There is | 25 | * task's vmacache pertains to a different mm (ie, its own). There is |