@@ -99,6 +99,50 @@ int randomize_va_space __read_mostly =
9999 2 ;
100100#endif
101101
102+ #ifndef track_pfn_vma_new
103+ /*
104+ * Interface that can be used by architecture code to keep track of
105+ * memory type of pfn mappings (remap_pfn_range, vm_insert_pfn)
106+ *
107+ * track_pfn_vma_new is called when a _new_ pfn mapping is being established
108+ * for physical range indicated by pfn and size.
109+ */
110+ int track_pfn_vma_new (struct vm_area_struct * vma , pgprot_t prot ,
111+ unsigned long pfn , unsigned long size )
112+ {
113+ return 0 ;
114+ }
115+ #endif
116+
117+ #ifndef track_pfn_vma_copy
118+ /*
119+ * Interface that can be used by architecture code to keep track of
120+ * memory type of pfn mappings (remap_pfn_range, vm_insert_pfn)
121+ *
122+ * track_pfn_vma_copy is called when vma that is covering the pfnmap gets
123+ * copied through copy_page_range().
124+ */
125+ int track_pfn_vma_copy (struct vm_area_struct * vma )
126+ {
127+ return 0 ;
128+ }
129+ #endif
130+
131+ #ifndef untrack_pfn_vma
132+ /*
133+ * Interface that can be used by architecture code to keep track of
134+ * memory type of pfn mappings (remap_pfn_range, vm_insert_pfn)
135+ *
136+ * untrack_pfn_vma is called while unmapping a pfnmap for a region.
137+ * untrack can be called for a specific region indicated by pfn and size or
138+ * can be for the entire vma (in which case size can be zero).
139+ */
140+ void untrack_pfn_vma (struct vm_area_struct * vma , unsigned long pfn ,
141+ unsigned long size )
142+ {
143+ }
144+ #endif
145+
102146static int __init disable_randmaps (char * s )
103147{
104148 randomize_va_space = 0 ;
@@ -669,6 +713,16 @@ int copy_page_range(struct mm_struct *dst_mm, struct mm_struct *src_mm,
669713 if (is_vm_hugetlb_page (vma ))
670714 return copy_hugetlb_page_range (dst_mm , src_mm , vma );
671715
716+ if (is_pfn_mapping (vma )) {
717+ /*
718+ * We do not free on error cases below as remove_vma
719+ * gets called on error from higher level routine
720+ */
721+ ret = track_pfn_vma_copy (vma );
722+ if (ret )
723+ return ret ;
724+ }
725+
672726 /*
673727 * We need to invalidate the secondary MMU mappings only when
674728 * there could be a permission downgrade on the ptes of the
@@ -915,6 +969,9 @@ unsigned long unmap_vmas(struct mmu_gather **tlbp,
915969 if (vma -> vm_flags & VM_ACCOUNT )
916970 * nr_accounted += (end - start ) >> PAGE_SHIFT ;
917971
972+ if (is_pfn_mapping (vma ))
973+ untrack_pfn_vma (vma , 0 , 0 );
974+
918975 while (start != end ) {
919976 if (!tlb_start_valid ) {
920977 tlb_start = start ;
@@ -1473,6 +1530,7 @@ static int insert_pfn(struct vm_area_struct *vma, unsigned long addr,
14731530int vm_insert_pfn (struct vm_area_struct * vma , unsigned long addr ,
14741531 unsigned long pfn )
14751532{
1533+ int ret ;
14761534 /*
14771535 * Technically, architectures with pte_special can avoid all these
14781536 * restrictions (same for remap_pfn_range). However we would like
@@ -1487,7 +1545,15 @@ int vm_insert_pfn(struct vm_area_struct *vma, unsigned long addr,
14871545
14881546 if (addr < vma -> vm_start || addr >= vma -> vm_end )
14891547 return - EFAULT ;
1490- return insert_pfn (vma , addr , pfn , vma -> vm_page_prot );
1548+ if (track_pfn_vma_new (vma , vma -> vm_page_prot , pfn , PAGE_SIZE ))
1549+ return - EINVAL ;
1550+
1551+ ret = insert_pfn (vma , addr , pfn , vma -> vm_page_prot );
1552+
1553+ if (ret )
1554+ untrack_pfn_vma (vma , pfn , PAGE_SIZE );
1555+
1556+ return ret ;
14911557}
14921558EXPORT_SYMBOL (vm_insert_pfn );
14931559
@@ -1625,6 +1691,10 @@ int remap_pfn_range(struct vm_area_struct *vma, unsigned long addr,
16251691
16261692 vma -> vm_flags |= VM_IO | VM_RESERVED | VM_PFNMAP ;
16271693
1694+ err = track_pfn_vma_new (vma , prot , pfn , PAGE_ALIGN (size ));
1695+ if (err )
1696+ return - EINVAL ;
1697+
16281698 BUG_ON (addr >= end );
16291699 pfn -= addr >> PAGE_SHIFT ;
16301700 pgd = pgd_offset (mm , addr );
@@ -1636,6 +1706,10 @@ int remap_pfn_range(struct vm_area_struct *vma, unsigned long addr,
16361706 if (err )
16371707 break ;
16381708 } while (pgd ++ , addr = next , addr != end );
1709+
1710+ if (err )
1711+ untrack_pfn_vma (vma , pfn , PAGE_ALIGN (size ));
1712+
16391713 return err ;
16401714}
16411715EXPORT_SYMBOL (remap_pfn_range );
0 commit comments