aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/proc/task_mmu.c69
1 files changed, 42 insertions, 27 deletions
diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c
index 7445980c8022..9d22c1c1caa8 100644
--- a/fs/proc/task_mmu.c
+++ b/fs/proc/task_mmu.c
@@ -122,6 +122,13 @@ struct mem_size_stats
122 unsigned long private_dirty; 122 unsigned long private_dirty;
123}; 123};
124 124
125struct pmd_walker {
126 struct vm_area_struct *vma;
127 void *private;
128 void (*action)(struct vm_area_struct *, pmd_t *, unsigned long,
129 unsigned long, void *);
130};
131
125static int show_map_internal(struct seq_file *m, void *v, struct mem_size_stats *mss) 132static int show_map_internal(struct seq_file *m, void *v, struct mem_size_stats *mss)
126{ 133{
127 struct proc_maps_private *priv = m->private; 134 struct proc_maps_private *priv = m->private;
@@ -204,16 +211,17 @@ static int show_map(struct seq_file *m, void *v)
204 return show_map_internal(m, v, NULL); 211 return show_map_internal(m, v, NULL);
205} 212}
206 213
207static void smaps_pte_range(struct vm_area_struct *vma, pmd_t *pmd, 214static void smaps_one_pmd(struct vm_area_struct *vma, pmd_t *pmd,
208 unsigned long addr, unsigned long end, 215 unsigned long addr, unsigned long end,
209 struct mem_size_stats *mss) 216 void *private)
210{ 217{
218 struct mem_size_stats *mss = private;
211 pte_t *pte, ptent; 219 pte_t *pte, ptent;
212 spinlock_t *ptl; 220 spinlock_t *ptl;
213 struct page *page; 221 struct page *page;
214 222
215 pte = pte_offset_map_lock(vma->vm_mm, pmd, addr, &ptl); 223 pte = pte_offset_map_lock(vma->vm_mm, pmd, addr, &ptl);
216 do { 224 for (; addr != end; pte++, addr += PAGE_SIZE) {
217 ptent = *pte; 225 ptent = *pte;
218 if (!pte_present(ptent)) 226 if (!pte_present(ptent))
219 continue; 227 continue;
@@ -235,57 +243,64 @@ static void smaps_pte_range(struct vm_area_struct *vma, pmd_t *pmd,
235 else 243 else
236 mss->private_clean += PAGE_SIZE; 244 mss->private_clean += PAGE_SIZE;
237 } 245 }
238 } while (pte++, addr += PAGE_SIZE, addr != end); 246 }
239 pte_unmap_unlock(pte - 1, ptl); 247 pte_unmap_unlock(pte - 1, ptl);
240 cond_resched(); 248 cond_resched();
241} 249}
242 250
243static inline void smaps_pmd_range(struct vm_area_struct *vma, pud_t *pud, 251static inline void for_each_pmd_in_pud(struct pmd_walker *walker, pud_t *pud,
244 unsigned long addr, unsigned long end, 252 unsigned long addr, unsigned long end)
245 struct mem_size_stats *mss)
246{ 253{
247 pmd_t *pmd; 254 pmd_t *pmd;
248 unsigned long next; 255 unsigned long next;
249 256
250 pmd = pmd_offset(pud, addr); 257 for (pmd = pmd_offset(pud, addr); addr != end;
251 do { 258 pmd++, addr = next) {
252 next = pmd_addr_end(addr, end); 259 next = pmd_addr_end(addr, end);
253 if (pmd_none_or_clear_bad(pmd)) 260 if (pmd_none_or_clear_bad(pmd))
254 continue; 261 continue;
255 smaps_pte_range(vma, pmd, addr, next, mss); 262 walker->action(walker->vma, pmd, addr, next, walker->private);
256 } while (pmd++, addr = next, addr != end); 263 }
257} 264}
258 265
259static inline void smaps_pud_range(struct vm_area_struct *vma, pgd_t *pgd, 266static inline void for_each_pud_in_pgd(struct pmd_walker *walker, pgd_t *pgd,
260 unsigned long addr, unsigned long end, 267 unsigned long addr, unsigned long end)
261 struct mem_size_stats *mss)
262{ 268{
263 pud_t *pud; 269 pud_t *pud;
264 unsigned long next; 270 unsigned long next;
265 271
266 pud = pud_offset(pgd, addr); 272 for (pud = pud_offset(pgd, addr); addr != end;
267 do { 273 pud++, addr = next) {
268 next = pud_addr_end(addr, end); 274 next = pud_addr_end(addr, end);
269 if (pud_none_or_clear_bad(pud)) 275 if (pud_none_or_clear_bad(pud))
270 continue; 276 continue;
271 smaps_pmd_range(vma, pud, addr, next, mss); 277 for_each_pmd_in_pud(walker, pud, addr, next);
272 } while (pud++, addr = next, addr != end); 278 }
273} 279}
274 280
275static inline void smaps_pgd_range(struct vm_area_struct *vma, 281static inline void for_each_pmd(struct vm_area_struct *vma,
276 unsigned long addr, unsigned long end, 282 void (*action)(struct vm_area_struct *, pmd_t *,
277 struct mem_size_stats *mss) 283 unsigned long, unsigned long,
284 void *),
285 void *private)
278{ 286{
287 unsigned long addr = vma->vm_start;
288 unsigned long end = vma->vm_end;
289 struct pmd_walker walker = {
290 .vma = vma,
291 .private = private,
292 .action = action,
293 };
279 pgd_t *pgd; 294 pgd_t *pgd;
280 unsigned long next; 295 unsigned long next;
281 296
282 pgd = pgd_offset(vma->vm_mm, addr); 297 for (pgd = pgd_offset(vma->vm_mm, addr); addr != end;
283 do { 298 pgd++, addr = next) {
284 next = pgd_addr_end(addr, end); 299 next = pgd_addr_end(addr, end);
285 if (pgd_none_or_clear_bad(pgd)) 300 if (pgd_none_or_clear_bad(pgd))
286 continue; 301 continue;
287 smaps_pud_range(vma, pgd, addr, next, mss); 302 for_each_pud_in_pgd(&walker, pgd, addr, next);
288 } while (pgd++, addr = next, addr != end); 303 }
289} 304}
290 305
291static int show_smap(struct seq_file *m, void *v) 306static int show_smap(struct seq_file *m, void *v)
@@ -295,7 +310,7 @@ static int show_smap(struct seq_file *m, void *v)
295 310
296 memset(&mss, 0, sizeof mss); 311 memset(&mss, 0, sizeof mss);
297 if (vma->vm_mm && !is_vm_hugetlb_page(vma)) 312 if (vma->vm_mm && !is_vm_hugetlb_page(vma))
298 smaps_pgd_range(vma, vma->vm_start, vma->vm_end, &mss); 313 for_each_pmd(vma, smaps_one_pmd, &mss);
299 return show_map_internal(m, v, &mss); 314 return show_map_internal(m, v, &mss);
300} 315}
301 316