On Thu, 21 May 2015, j.gli...@gmail.com wrote:

> From: Jérôme Glisse <jgli...@redhat.com>
> 
> Listener of mm event might not have easy way to get the struct page
> behind and address invalidated with mmu_notifier_invalidate_page()

s/behind and address/behind an address/

> function as this happens after the cpu page table have been clear/
> updated. This happens for instance if the listener is storing a dma
> mapping inside its secondary page table. To avoid complex reverse
> dma mapping lookup just pass along a pointer to the page being
> invalidated.
> 
> Signed-off-by: Jérôme Glisse <jgli...@redhat.com>
> ---
>  drivers/infiniband/core/umem_odp.c | 1 +
>  drivers/iommu/amd_iommu_v2.c       | 1 +
>  drivers/misc/sgi-gru/grutlbpurge.c | 1 +
>  drivers/xen/gntdev.c               | 1 +
>  include/linux/mmu_notifier.h       | 6 +++++-
>  mm/mmu_notifier.c                  | 3 ++-
>  mm/rmap.c                          | 4 ++--
>  virt/kvm/kvm_main.c                | 1 +
>  8 files changed, 14 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/infiniband/core/umem_odp.c 
> b/drivers/infiniband/core/umem_odp.c
> index 8f7f845..d10dd88 100644
> --- a/drivers/infiniband/core/umem_odp.c
> +++ b/drivers/infiniband/core/umem_odp.c
> @@ -166,6 +166,7 @@ static int invalidate_page_trampoline(struct ib_umem 
> *item, u64 start,
>  static void ib_umem_notifier_invalidate_page(struct mmu_notifier *mn,
>                                            struct mm_struct *mm,
>                                            unsigned long address,
> +                                          struct page *page,
>                                            enum mmu_event event)
>  {
>       struct ib_ucontext *context = container_of(mn, struct ib_ucontext, mn);
> diff --git a/drivers/iommu/amd_iommu_v2.c b/drivers/iommu/amd_iommu_v2.c
> index 4aa4de6..de3c540 100644
> --- a/drivers/iommu/amd_iommu_v2.c
> +++ b/drivers/iommu/amd_iommu_v2.c
> @@ -385,6 +385,7 @@ static int mn_clear_flush_young(struct mmu_notifier *mn,
>  static void mn_invalidate_page(struct mmu_notifier *mn,
>                              struct mm_struct *mm,
>                              unsigned long address,
> +                            struct page *page,
>                              enum mmu_event event)
>  {
>       __mn_flush_page(mn, address);
> diff --git a/drivers/misc/sgi-gru/grutlbpurge.c 
> b/drivers/misc/sgi-gru/grutlbpurge.c
> index 44b41b7..c7659b76 100644
> --- a/drivers/misc/sgi-gru/grutlbpurge.c
> +++ b/drivers/misc/sgi-gru/grutlbpurge.c
> @@ -250,6 +250,7 @@ static void gru_invalidate_range_end(struct mmu_notifier 
> *mn,
>  
>  static void gru_invalidate_page(struct mmu_notifier *mn, struct mm_struct 
> *mm,
>                               unsigned long address,
> +                             struct page *page,
>                               enum mmu_event event)
>  {
>       struct gru_mm_struct *gms = container_of(mn, struct gru_mm_struct,
> diff --git a/drivers/xen/gntdev.c b/drivers/xen/gntdev.c
> index 0e8aa12..90693ce 100644
> --- a/drivers/xen/gntdev.c
> +++ b/drivers/xen/gntdev.c
> @@ -485,6 +485,7 @@ static void mn_invl_range_start(struct mmu_notifier *mn,
>  static void mn_invl_page(struct mmu_notifier *mn,
>                        struct mm_struct *mm,
>                        unsigned long address,
> +                      struct page *page,
>                        enum mmu_event event)
>  {
>       struct mmu_notifier_range range;
> diff --git a/include/linux/mmu_notifier.h b/include/linux/mmu_notifier.h
> index ada3ed1..283ad26 100644
> --- a/include/linux/mmu_notifier.h
> +++ b/include/linux/mmu_notifier.h
> @@ -172,6 +172,7 @@ struct mmu_notifier_ops {
>       void (*invalidate_page)(struct mmu_notifier *mn,
>                               struct mm_struct *mm,
>                               unsigned long address,
> +                             struct page *page,
>                               enum mmu_event event);
>  
>       /*
> @@ -290,6 +291,7 @@ extern void __mmu_notifier_change_pte(struct mm_struct 
> *mm,
>                                     enum mmu_event event);
>  extern void __mmu_notifier_invalidate_page(struct mm_struct *mm,
>                                         unsigned long address,
> +                                       struct page *page,
>                                         enum mmu_event event);
>  extern void __mmu_notifier_invalidate_range_start(struct mm_struct *mm,
>                                                 struct mmu_notifier_range 
> *range);
> @@ -338,10 +340,11 @@ static inline void mmu_notifier_change_pte(struct 
> mm_struct *mm,
>  
>  static inline void mmu_notifier_invalidate_page(struct mm_struct *mm,
>                                               unsigned long address,
> +                                             struct page *page,
>                                               enum mmu_event event)
>  {
>       if (mm_has_notifiers(mm))
> -             __mmu_notifier_invalidate_page(mm, address, event);
> +             __mmu_notifier_invalidate_page(mm, address, page, event);
>  }
>  
>  static inline void mmu_notifier_invalidate_range_start(struct mm_struct *mm,
> @@ -492,6 +495,7 @@ static inline void mmu_notifier_change_pte(struct 
> mm_struct *mm,
>  
>  static inline void mmu_notifier_invalidate_page(struct mm_struct *mm,
>                                               unsigned long address,
> +                                             struct page *page,
>                                               enum mmu_event event)
>  {
>  }
> diff --git a/mm/mmu_notifier.c b/mm/mmu_notifier.c
> index 294ebc4..2ff6d43 100644
> --- a/mm/mmu_notifier.c
> +++ b/mm/mmu_notifier.c
> @@ -160,6 +160,7 @@ void __mmu_notifier_change_pte(struct mm_struct *mm,
>  
>  void __mmu_notifier_invalidate_page(struct mm_struct *mm,
>                                   unsigned long address,
> +                                 struct page *page,
>                                   enum mmu_event event)
>  {
>       struct mmu_notifier *mn;
> @@ -168,7 +169,7 @@ void __mmu_notifier_invalidate_page(struct mm_struct *mm,
>       id = srcu_read_lock(&srcu);
>       hlist_for_each_entry_rcu(mn, &mm->mmu_notifier_mm->list, hlist) {
>               if (mn->ops->invalidate_page)
> -                     mn->ops->invalidate_page(mn, mm, address, event);
> +                     mn->ops->invalidate_page(mn, mm, address, page, event);
>       }
>       srcu_read_unlock(&srcu, id);
>  }
> diff --git a/mm/rmap.c b/mm/rmap.c
> index 74c51e0..4563edc 100644
> --- a/mm/rmap.c
> +++ b/mm/rmap.c
> @@ -915,7 +915,7 @@ static int page_mkclean_one(struct page *page, struct 
> vm_area_struct *vma,
>       pte_unmap_unlock(pte, ptl);
>  
>       if (ret) {
> -             mmu_notifier_invalidate_page(mm, address, MMU_WRITE_BACK);
> +             mmu_notifier_invalidate_page(mm, address, page, MMU_WRITE_BACK);
>               (*cleaned)++;
>       }
>  out:
> @@ -1338,7 +1338,7 @@ discard:
>  out_unmap:
>       pte_unmap_unlock(pte, ptl);
>       if (ret != SWAP_FAIL && !(flags & TTU_MUNLOCK))
> -             mmu_notifier_invalidate_page(mm, address, MMU_MIGRATE);
> +             mmu_notifier_invalidate_page(mm, address, page, MMU_MIGRATE);
>  out:
>       return ret;
>  
> diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
> index 6177c56..62978ed 100644
> --- a/virt/kvm/kvm_main.c
> +++ b/virt/kvm/kvm_main.c
> @@ -261,6 +261,7 @@ static inline struct kvm *mmu_notifier_to_kvm(struct 
> mmu_notifier *mn)
>  static void kvm_mmu_notifier_invalidate_page(struct mmu_notifier *mn,
>                                            struct mm_struct *mm,
>                                            unsigned long address,
> +                                          struct page *page,
>                                            enum mmu_event event)
>  {
>       struct kvm *kvm = mmu_notifier_to_kvm(mn);
> -- 
> 1.9.3
> 
> 

This seems like a reasonable thing to do, and I didn't spot any problems 
in the patch.

thanks,
John H.

Reply via email to