~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/mm/mapping_dirty_helpers.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

Diff markup

Differences between /mm/mapping_dirty_helpers.c (Version linux-6.11.5) and /mm/mapping_dirty_helpers.c (Version linux-5.3.18)


  1 // SPDX-License-Identifier: GPL-2.0                 1 
  2 #include <linux/pagewalk.h>                       
  3 #include <linux/hugetlb.h>                        
  4 #include <linux/bitops.h>                         
  5 #include <linux/mmu_notifier.h>                   
  6 #include <linux/mm_inline.h>                      
  7 #include <asm/cacheflush.h>                       
  8 #include <asm/tlbflush.h>                         
  9                                                   
 10 /**                                               
 11  * struct wp_walk - Private struct for pagetab    
 12  * @range: Range for mmu notifiers                
 13  * @tlbflush_start: Address of first modified     
 14  * @tlbflush_end: Address of last modified pte    
 15  * @total: Total number of modified ptes          
 16  */                                               
 17 struct wp_walk {                                  
 18         struct mmu_notifier_range range;          
 19         unsigned long tlbflush_start;             
 20         unsigned long tlbflush_end;               
 21         unsigned long total;                      
 22 };                                                
 23                                                   
 24 /**                                               
 25  * wp_pte - Write-protect a pte                   
 26  * @pte: Pointer to the pte                       
 27  * @addr: The start of protecting virtual addr    
 28  * @end: The end of protecting virtual address    
 29  * @walk: pagetable walk callback argument        
 30  *                                                
 31  * The function write-protects a pte and recor    
 32  * virtual address space of touched ptes for e    
 33  */                                               
 34 static int wp_pte(pte_t *pte, unsigned long ad    
 35                   struct mm_walk *walk)           
 36 {                                                 
 37         struct wp_walk *wpwalk = walk->private    
 38         pte_t ptent = ptep_get(pte);              
 39                                                   
 40         if (pte_write(ptent)) {                   
 41                 pte_t old_pte = ptep_modify_pr    
 42                                                   
 43                 ptent = pte_wrprotect(old_pte)    
 44                 ptep_modify_prot_commit(walk->    
 45                 wpwalk->total++;                  
 46                 wpwalk->tlbflush_start = min(w    
 47                 wpwalk->tlbflush_end = max(wpw    
 48                                            add    
 49         }                                         
 50                                                   
 51         return 0;                                 
 52 }                                                 
 53                                                   
 54 /**                                               
 55  * struct clean_walk - Private struct for the     
 56  * @base: struct wp_walk we derive from           
 57  * @bitmap_pgoff: Address_space Page offset of    
 58  * @bitmap: Bitmap with one bit for each page     
 59  * covered.                                       
 60  * @start: Address_space page offset of first     
 61  * to @bitmap_pgoff                               
 62  * @end: Address_space page offset of last mod    
 63  * to @bitmap_pgoff                               
 64  */                                               
 65 struct clean_walk {                               
 66         struct wp_walk base;                      
 67         pgoff_t bitmap_pgoff;                     
 68         unsigned long *bitmap;                    
 69         pgoff_t start;                            
 70         pgoff_t end;                              
 71 };                                                
 72                                                   
 73 #define to_clean_walk(_wpwalk) container_of(_w    
 74                                                   
 75 /**                                               
 76  * clean_record_pte - Clean a pte and record i    
 77  * bitmap                                         
 78  * @pte: Pointer to the pte                       
 79  * @addr: The start of virtual address to be c    
 80  * @end: The end of virtual address to be clea    
 81  * @walk: pagetable walk callback argument        
 82  *                                                
 83  * The function cleans a pte and records the r    
 84  * virtual address space of touched ptes for e    
 85  * It also records dirty ptes in a bitmap repr    
 86  * in the address_space, as well as the first     
 87  * touched.                                       
 88  */                                               
 89 static int clean_record_pte(pte_t *pte, unsign    
 90                             unsigned long end,    
 91 {                                                 
 92         struct wp_walk *wpwalk = walk->private    
 93         struct clean_walk *cwalk = to_clean_wa    
 94         pte_t ptent = ptep_get(pte);              
 95                                                   
 96         if (pte_dirty(ptent)) {                   
 97                 pgoff_t pgoff = ((addr - walk-    
 98                         walk->vma->vm_pgoff -     
 99                 pte_t old_pte = ptep_modify_pr    
100                                                   
101                 ptent = pte_mkclean(old_pte);     
102                 ptep_modify_prot_commit(walk->    
103                                                   
104                 wpwalk->total++;                  
105                 wpwalk->tlbflush_start = min(w    
106                 wpwalk->tlbflush_end = max(wpw    
107                                            add    
108                                                   
109                 __set_bit(pgoff, cwalk->bitmap    
110                 cwalk->start = min(cwalk->star    
111                 cwalk->end = max(cwalk->end, p    
112         }                                         
113                                                   
114         return 0;                                 
115 }                                                 
116                                                   
117 /*                                                
118  * wp_clean_pmd_entry - The pagewalk pmd callb    
119  *                                                
120  * Dirty-tracking should take place on the PTE    
121  * WARN() if encountering a dirty huge pmd.       
122  * Furthermore, never split huge pmds, since t    
123  * causes dirty info loss. The pagefault handl    
124  * that if needed.                                
125  */                                               
126 static int wp_clean_pmd_entry(pmd_t *pmd, unsi    
127                               struct mm_walk *    
128 {                                                 
129         pmd_t pmdval = pmdp_get_lockless(pmd);    
130                                                   
131         /* Do not split a huge pmd, present or    
132         if (pmd_trans_huge(pmdval) || pmd_devm    
133                 WARN_ON(pmd_write(pmdval) || p    
134                 walk->action = ACTION_CONTINUE    
135         }                                         
136         return 0;                                 
137 }                                                 
138                                                   
139 /*                                                
140  * wp_clean_pud_entry - The pagewalk pud callb    
141  *                                                
142  * Dirty-tracking should take place on the PTE    
143  * WARN() if encountering a dirty huge puds.      
144  * Furthermore, never split huge puds, since t    
145  * causes dirty info loss. The pagefault handl    
146  * that if needed.                                
147  */                                               
148 static int wp_clean_pud_entry(pud_t *pud, unsi    
149                               struct mm_walk *    
150 {                                                 
151 #ifdef CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE_P    
152         pud_t pudval = READ_ONCE(*pud);           
153                                                   
154         /* Do not split a huge pud */             
155         if (pud_trans_huge(pudval) || pud_devm    
156                 WARN_ON(pud_write(pudval) || p    
157                 walk->action = ACTION_CONTINUE    
158         }                                         
159 #endif                                            
160         return 0;                                 
161 }                                                 
162                                                   
163 /*                                                
164  * wp_clean_pre_vma - The pagewalk pre_vma cal    
165  *                                                
166  * The pre_vma callback performs the cache flu    
167  * and calls the necessary mmu notifiers.         
168  */                                               
169 static int wp_clean_pre_vma(unsigned long star    
170                             struct mm_walk *wa    
171 {                                                 
172         struct wp_walk *wpwalk = walk->private    
173                                                   
174         wpwalk->tlbflush_start = end;             
175         wpwalk->tlbflush_end = start;             
176                                                   
177         mmu_notifier_range_init(&wpwalk->range    
178                                 walk->mm, star    
179         mmu_notifier_invalidate_range_start(&w    
180         flush_cache_range(walk->vma, start, en    
181                                                   
182         /*                                        
183          * We're not using tlb_gather_mmu() si    
184          * only a small subrange of PTEs are a    
185          * tlb_gather_mmu() records the full r    
186          */                                       
187         inc_tlb_flush_pending(walk->mm);          
188                                                   
189         return 0;                                 
190 }                                                 
191                                                   
192 /*                                                
193  * wp_clean_post_vma - The pagewalk post_vma c    
194  *                                                
195  * The post_vma callback performs the tlb flus    
196  * notifiers.                                     
197  */                                               
198 static void wp_clean_post_vma(struct mm_walk *    
199 {                                                 
200         struct wp_walk *wpwalk = walk->private    
201                                                   
202         if (mm_tlb_flush_nested(walk->mm))        
203                 flush_tlb_range(walk->vma, wpw    
204                                 wpwalk->range.    
205         else if (wpwalk->tlbflush_end > wpwalk    
206                 flush_tlb_range(walk->vma, wpw    
207                                 wpwalk->tlbflu    
208                                                   
209         mmu_notifier_invalidate_range_end(&wpw    
210         dec_tlb_flush_pending(walk->mm);          
211 }                                                 
212                                                   
213 /*                                                
214  * wp_clean_test_walk - The pagewalk test_walk    
215  *                                                
216  * Won't perform dirty-tracking on COW, read-o    
217  */                                               
218 static int wp_clean_test_walk(unsigned long st    
219                               struct mm_walk *    
220 {                                                 
221         unsigned long vm_flags = READ_ONCE(wal    
222                                                   
223         /* Skip non-applicable VMAs */            
224         if ((vm_flags & (VM_SHARED | VM_MAYWRI    
225             (VM_SHARED | VM_MAYWRITE))            
226                 return 1;                         
227                                                   
228         return 0;                                 
229 }                                                 
230                                                   
231 static const struct mm_walk_ops clean_walk_ops    
232         .pte_entry = clean_record_pte,            
233         .pmd_entry = wp_clean_pmd_entry,          
234         .pud_entry = wp_clean_pud_entry,          
235         .test_walk = wp_clean_test_walk,          
236         .pre_vma = wp_clean_pre_vma,              
237         .post_vma = wp_clean_post_vma             
238 };                                                
239                                                   
240 static const struct mm_walk_ops wp_walk_ops =     
241         .pte_entry = wp_pte,                      
242         .pmd_entry = wp_clean_pmd_entry,          
243         .pud_entry = wp_clean_pud_entry,          
244         .test_walk = wp_clean_test_walk,          
245         .pre_vma = wp_clean_pre_vma,              
246         .post_vma = wp_clean_post_vma             
247 };                                                
248                                                   
249 /**                                               
250  * wp_shared_mapping_range - Write-protect all    
251  * @mapping: The address_space we want to writ    
252  * @first_index: The first page offset in the     
253  * @nr: Number of incremental page offsets to     
254  *                                                
255  * Note: This function currently skips transhu    
256  * it's intended for dirty-tracking on the PTE    
257  * encountering transhuge write-enabled entrie    
258  * extended to handle them as well.               
259  *                                                
260  * Return: The number of ptes actually write-p    
261  * already write-protected ptes are not counte    
262  */                                               
263 unsigned long wp_shared_mapping_range(struct a    
264                                       pgoff_t     
265 {                                                 
266         struct wp_walk wpwalk = { .total = 0 }    
267                                                   
268         i_mmap_lock_read(mapping);                
269         WARN_ON(walk_page_mapping(mapping, fir    
270                                   &wpwalk));      
271         i_mmap_unlock_read(mapping);              
272                                                   
273         return wpwalk.total;                      
274 }                                                 
275 EXPORT_SYMBOL_GPL(wp_shared_mapping_range);       
276                                                   
277 /**                                               
278  * clean_record_shared_mapping_range - Clean a    
279  * address space range                            
280  * @mapping: The address_space we want to clea    
281  * @first_index: The first page offset in the     
282  * @nr: Number of incremental page offsets to     
283  * @bitmap_pgoff: The page offset of the first    
284  * @bitmap: Pointer to a bitmap of at least @n    
285  * cover the whole range @first_index..@first_    
286  * @start: Pointer to number of the first set     
287  * is modified as new bits are set by the func    
288  * @end: Pointer to the number of the last set    
289  * none set. The value is modified as new bits    
290  *                                                
291  * When this function returns there is no guar    
292  * not already dirtied new ptes. However it wi    
293  * reported in the bitmap. The guarantees are     
294  *                                                
295  * * All ptes dirty when the function starts e    
296  *   in the bitmap.                               
297  * * All ptes dirtied after that will either r    
298  *   bitmap or both.                              
299  *                                                
300  * If a caller needs to make sure all dirty pt    
301  * additional are added, it first needs to wri    
302  * range and make sure new writers are blocked    
303  * pfn_mkwrite(). And then after a TLB flush f    
304  * pick up all dirty bits.                        
305  *                                                
306  * This function currently skips transhuge pag    
307  * it's intended for dirty-tracking on the PTE    
308  * encountering transhuge dirty entries, thoug    
309  * to handle them as well.                        
310  *                                                
311  * Return: The number of dirty ptes actually c    
312  */                                               
313 unsigned long clean_record_shared_mapping_rang    
314                                                   
315                                                   
316                                                   
317                                                   
318                                                   
319 {                                                 
320         bool none_set = (*start >= *end);         
321         struct clean_walk cwalk = {               
322                 .base = { .total = 0 },           
323                 .bitmap_pgoff = bitmap_pgoff,     
324                 .bitmap = bitmap,                 
325                 .start = none_set ? nr : *star    
326                 .end = none_set ? 0 : *end,       
327         };                                        
328                                                   
329         i_mmap_lock_read(mapping);                
330         WARN_ON(walk_page_mapping(mapping, fir    
331                                   &cwalk.base)    
332         i_mmap_unlock_read(mapping);              
333                                                   
334         *start = cwalk.start;                     
335         *end = cwalk.end;                         
336                                                   
337         return cwalk.base.total;                  
338 }                                                 
339 EXPORT_SYMBOL_GPL(clean_record_shared_mapping_    
340                                                   

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php