Unlike the mm of a task, an mshare host mm is not updated on context switch. In particular this means that mm_cpumask is never updated which results in TLB flushes for updates to mshare PTEs only being done on the local CPU. To ensure entries are flushed for non-local TLBs, set up an mmu notifier on the mshare mm and use the .arch_invalidate_secondary_tlbs callback to flush all TLBs. arch_invalidate_secondary_tlbs guarantees that TLB entries will be flushed before pages are freed when unmapping pages in an mshare region. Signed-off-by: Anthony Yznaga <anthony.yznaga@xxxxxxxxxx> --- mm/mshare.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/mm/mshare.c b/mm/mshare.c index 529a90fe1602..8dca4199dd01 100644 --- a/mm/mshare.c +++ b/mm/mshare.c @@ -17,9 +17,11 @@ #include <linux/fs.h> #include <linux/fs_context.h> #include <linux/mman.h> +#include <linux/mmu_notifier.h> #include <linux/spinlock_types.h> #include <uapi/linux/magic.h> #include <uapi/linux/msharefs.h> +#include <asm/tlbflush.h> const unsigned long mshare_align = P4D_SIZE; @@ -27,6 +29,17 @@ struct mshare_data { struct mm_struct *mm; spinlock_t m_lock; struct mshare_info minfo; + struct mmu_notifier mn; +}; + +static void mshare_invalidate_tlbs(struct mmu_notifier *mn, struct mm_struct *mm, + unsigned long start, unsigned long end) +{ + flush_tlb_all(); +} + +static const struct mmu_notifier_ops mshare_mmu_ops = { + .arch_invalidate_secondary_tlbs = mshare_invalidate_tlbs, }; static int mshare_vm_op_split(struct vm_area_struct *vma, unsigned long addr) @@ -191,6 +204,10 @@ msharefs_fill_mm(struct inode *inode) m_data->mm = mm; spin_lock_init(&m_data->m_lock); inode->i_private = m_data; + m_data->mn.ops = &mshare_mmu_ops; + ret = mmu_notifier_register(&m_data->mn, mm); + if (ret) + goto err_free; return 0; -- 2.43.5