|
@@ -253,6 +253,7 @@ static int proc_map_release(struct inode *inode, struct file *file)
|
|
if (priv->mm)
|
|
if (priv->mm)
|
|
mmdrop(priv->mm);
|
|
mmdrop(priv->mm);
|
|
|
|
|
|
|
|
+ kfree(priv->rollup);
|
|
return seq_release_private(inode, file);
|
|
return seq_release_private(inode, file);
|
|
}
|
|
}
|
|
|
|
|
|
@@ -279,6 +280,23 @@ static int is_stack(struct proc_maps_private *priv,
|
|
vma->vm_end >= vma->vm_mm->start_stack;
|
|
vma->vm_end >= vma->vm_mm->start_stack;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static void show_vma_header_prefix(struct seq_file *m,
|
|
|
|
+ unsigned long start, unsigned long end,
|
|
|
|
+ vm_flags_t flags, unsigned long long pgoff,
|
|
|
|
+ dev_t dev, unsigned long ino)
|
|
|
|
+{
|
|
|
|
+ seq_setwidth(m, 25 + sizeof(void *) * 6 - 1);
|
|
|
|
+ seq_printf(m, "%08lx-%08lx %c%c%c%c %08llx %02x:%02x %lu ",
|
|
|
|
+ start,
|
|
|
|
+ end,
|
|
|
|
+ flags & VM_READ ? 'r' : '-',
|
|
|
|
+ flags & VM_WRITE ? 'w' : '-',
|
|
|
|
+ flags & VM_EXEC ? 'x' : '-',
|
|
|
|
+ flags & VM_MAYSHARE ? 's' : 'p',
|
|
|
|
+ pgoff,
|
|
|
|
+ MAJOR(dev), MINOR(dev), ino);
|
|
|
|
+}
|
|
|
|
+
|
|
static void
|
|
static void
|
|
show_map_vma(struct seq_file *m, struct vm_area_struct *vma, int is_pid)
|
|
show_map_vma(struct seq_file *m, struct vm_area_struct *vma, int is_pid)
|
|
{
|
|
{
|
|
@@ -301,17 +319,7 @@ show_map_vma(struct seq_file *m, struct vm_area_struct *vma, int is_pid)
|
|
|
|
|
|
start = vma->vm_start;
|
|
start = vma->vm_start;
|
|
end = vma->vm_end;
|
|
end = vma->vm_end;
|
|
-
|
|
|
|
- seq_setwidth(m, 25 + sizeof(void *) * 6 - 1);
|
|
|
|
- seq_printf(m, "%08lx-%08lx %c%c%c%c %08llx %02x:%02x %lu ",
|
|
|
|
- start,
|
|
|
|
- end,
|
|
|
|
- flags & VM_READ ? 'r' : '-',
|
|
|
|
- flags & VM_WRITE ? 'w' : '-',
|
|
|
|
- flags & VM_EXEC ? 'x' : '-',
|
|
|
|
- flags & VM_MAYSHARE ? 's' : 'p',
|
|
|
|
- pgoff,
|
|
|
|
- MAJOR(dev), MINOR(dev), ino);
|
|
|
|
|
|
+ show_vma_header_prefix(m, start, end, flags, pgoff, dev, ino);
|
|
|
|
|
|
/*
|
|
/*
|
|
* Print the dentry name for named mappings, and a
|
|
* Print the dentry name for named mappings, and a
|
|
@@ -430,6 +438,7 @@ const struct file_operations proc_tid_maps_operations = {
|
|
|
|
|
|
#ifdef CONFIG_PROC_PAGE_MONITOR
|
|
#ifdef CONFIG_PROC_PAGE_MONITOR
|
|
struct mem_size_stats {
|
|
struct mem_size_stats {
|
|
|
|
+ bool first;
|
|
unsigned long resident;
|
|
unsigned long resident;
|
|
unsigned long shared_clean;
|
|
unsigned long shared_clean;
|
|
unsigned long shared_dirty;
|
|
unsigned long shared_dirty;
|
|
@@ -443,7 +452,9 @@ struct mem_size_stats {
|
|
unsigned long swap;
|
|
unsigned long swap;
|
|
unsigned long shared_hugetlb;
|
|
unsigned long shared_hugetlb;
|
|
unsigned long private_hugetlb;
|
|
unsigned long private_hugetlb;
|
|
|
|
+ unsigned long first_vma_start;
|
|
u64 pss;
|
|
u64 pss;
|
|
|
|
+ u64 pss_locked;
|
|
u64 swap_pss;
|
|
u64 swap_pss;
|
|
bool check_shmem_swap;
|
|
bool check_shmem_swap;
|
|
};
|
|
};
|
|
@@ -719,18 +730,36 @@ void __weak arch_show_smap(struct seq_file *m, struct vm_area_struct *vma)
|
|
|
|
|
|
static int show_smap(struct seq_file *m, void *v, int is_pid)
|
|
static int show_smap(struct seq_file *m, void *v, int is_pid)
|
|
{
|
|
{
|
|
|
|
+ struct proc_maps_private *priv = m->private;
|
|
struct vm_area_struct *vma = v;
|
|
struct vm_area_struct *vma = v;
|
|
- struct mem_size_stats mss;
|
|
|
|
|
|
+ struct mem_size_stats mss_stack;
|
|
|
|
+ struct mem_size_stats *mss;
|
|
struct mm_walk smaps_walk = {
|
|
struct mm_walk smaps_walk = {
|
|
.pmd_entry = smaps_pte_range,
|
|
.pmd_entry = smaps_pte_range,
|
|
#ifdef CONFIG_HUGETLB_PAGE
|
|
#ifdef CONFIG_HUGETLB_PAGE
|
|
.hugetlb_entry = smaps_hugetlb_range,
|
|
.hugetlb_entry = smaps_hugetlb_range,
|
|
#endif
|
|
#endif
|
|
.mm = vma->vm_mm,
|
|
.mm = vma->vm_mm,
|
|
- .private = &mss,
|
|
|
|
};
|
|
};
|
|
|
|
+ int ret = 0;
|
|
|
|
+ bool rollup_mode;
|
|
|
|
+ bool last_vma;
|
|
|
|
+
|
|
|
|
+ if (priv->rollup) {
|
|
|
|
+ rollup_mode = true;
|
|
|
|
+ mss = priv->rollup;
|
|
|
|
+ if (mss->first) {
|
|
|
|
+ mss->first_vma_start = vma->vm_start;
|
|
|
|
+ mss->first = false;
|
|
|
|
+ }
|
|
|
|
+ last_vma = !m_next_vma(priv, vma);
|
|
|
|
+ } else {
|
|
|
|
+ rollup_mode = false;
|
|
|
|
+ memset(&mss_stack, 0, sizeof(mss_stack));
|
|
|
|
+ mss = &mss_stack;
|
|
|
|
+ }
|
|
|
|
|
|
- memset(&mss, 0, sizeof mss);
|
|
|
|
|
|
+ smaps_walk.private = mss;
|
|
|
|
|
|
#ifdef CONFIG_SHMEM
|
|
#ifdef CONFIG_SHMEM
|
|
if (vma->vm_file && shmem_mapping(vma->vm_file->f_mapping)) {
|
|
if (vma->vm_file && shmem_mapping(vma->vm_file->f_mapping)) {
|
|
@@ -748,9 +777,9 @@ static int show_smap(struct seq_file *m, void *v, int is_pid)
|
|
|
|
|
|
if (!shmem_swapped || (vma->vm_flags & VM_SHARED) ||
|
|
if (!shmem_swapped || (vma->vm_flags & VM_SHARED) ||
|
|
!(vma->vm_flags & VM_WRITE)) {
|
|
!(vma->vm_flags & VM_WRITE)) {
|
|
- mss.swap = shmem_swapped;
|
|
|
|
|
|
+ mss->swap = shmem_swapped;
|
|
} else {
|
|
} else {
|
|
- mss.check_shmem_swap = true;
|
|
|
|
|
|
+ mss->check_shmem_swap = true;
|
|
smaps_walk.pte_hole = smaps_pte_hole;
|
|
smaps_walk.pte_hole = smaps_pte_hole;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@@ -758,54 +787,71 @@ static int show_smap(struct seq_file *m, void *v, int is_pid)
|
|
|
|
|
|
/* mmap_sem is held in m_start */
|
|
/* mmap_sem is held in m_start */
|
|
walk_page_vma(vma, &smaps_walk);
|
|
walk_page_vma(vma, &smaps_walk);
|
|
|
|
+ if (vma->vm_flags & VM_LOCKED)
|
|
|
|
+ mss->pss_locked += mss->pss;
|
|
|
|
+
|
|
|
|
+ if (!rollup_mode) {
|
|
|
|
+ show_map_vma(m, vma, is_pid);
|
|
|
|
+ } else if (last_vma) {
|
|
|
|
+ show_vma_header_prefix(
|
|
|
|
+ m, mss->first_vma_start, vma->vm_end, 0, 0, 0, 0);
|
|
|
|
+ seq_pad(m, ' ');
|
|
|
|
+ seq_puts(m, "[rollup]\n");
|
|
|
|
+ } else {
|
|
|
|
+ ret = SEQ_SKIP;
|
|
|
|
+ }
|
|
|
|
|
|
- show_map_vma(m, vma, is_pid);
|
|
|
|
-
|
|
|
|
- seq_printf(m,
|
|
|
|
- "Size: %8lu kB\n"
|
|
|
|
- "Rss: %8lu kB\n"
|
|
|
|
- "Pss: %8lu kB\n"
|
|
|
|
- "Shared_Clean: %8lu kB\n"
|
|
|
|
- "Shared_Dirty: %8lu kB\n"
|
|
|
|
- "Private_Clean: %8lu kB\n"
|
|
|
|
- "Private_Dirty: %8lu kB\n"
|
|
|
|
- "Referenced: %8lu kB\n"
|
|
|
|
- "Anonymous: %8lu kB\n"
|
|
|
|
- "LazyFree: %8lu kB\n"
|
|
|
|
- "AnonHugePages: %8lu kB\n"
|
|
|
|
- "ShmemPmdMapped: %8lu kB\n"
|
|
|
|
- "Shared_Hugetlb: %8lu kB\n"
|
|
|
|
- "Private_Hugetlb: %7lu kB\n"
|
|
|
|
- "Swap: %8lu kB\n"
|
|
|
|
- "SwapPss: %8lu kB\n"
|
|
|
|
- "KernelPageSize: %8lu kB\n"
|
|
|
|
- "MMUPageSize: %8lu kB\n"
|
|
|
|
- "Locked: %8lu kB\n",
|
|
|
|
- (vma->vm_end - vma->vm_start) >> 10,
|
|
|
|
- mss.resident >> 10,
|
|
|
|
- (unsigned long)(mss.pss >> (10 + PSS_SHIFT)),
|
|
|
|
- mss.shared_clean >> 10,
|
|
|
|
- mss.shared_dirty >> 10,
|
|
|
|
- mss.private_clean >> 10,
|
|
|
|
- mss.private_dirty >> 10,
|
|
|
|
- mss.referenced >> 10,
|
|
|
|
- mss.anonymous >> 10,
|
|
|
|
- mss.lazyfree >> 10,
|
|
|
|
- mss.anonymous_thp >> 10,
|
|
|
|
- mss.shmem_thp >> 10,
|
|
|
|
- mss.shared_hugetlb >> 10,
|
|
|
|
- mss.private_hugetlb >> 10,
|
|
|
|
- mss.swap >> 10,
|
|
|
|
- (unsigned long)(mss.swap_pss >> (10 + PSS_SHIFT)),
|
|
|
|
- vma_kernel_pagesize(vma) >> 10,
|
|
|
|
- vma_mmu_pagesize(vma) >> 10,
|
|
|
|
- (vma->vm_flags & VM_LOCKED) ?
|
|
|
|
- (unsigned long)(mss.pss >> (10 + PSS_SHIFT)) : 0);
|
|
|
|
-
|
|
|
|
- arch_show_smap(m, vma);
|
|
|
|
- show_smap_vma_flags(m, vma);
|
|
|
|
|
|
+ if (!rollup_mode)
|
|
|
|
+ seq_printf(m,
|
|
|
|
+ "Size: %8lu kB\n"
|
|
|
|
+ "KernelPageSize: %8lu kB\n"
|
|
|
|
+ "MMUPageSize: %8lu kB\n",
|
|
|
|
+ (vma->vm_end - vma->vm_start) >> 10,
|
|
|
|
+ vma_kernel_pagesize(vma) >> 10,
|
|
|
|
+ vma_mmu_pagesize(vma) >> 10);
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ if (!rollup_mode || last_vma)
|
|
|
|
+ seq_printf(m,
|
|
|
|
+ "Rss: %8lu kB\n"
|
|
|
|
+ "Pss: %8lu kB\n"
|
|
|
|
+ "Shared_Clean: %8lu kB\n"
|
|
|
|
+ "Shared_Dirty: %8lu kB\n"
|
|
|
|
+ "Private_Clean: %8lu kB\n"
|
|
|
|
+ "Private_Dirty: %8lu kB\n"
|
|
|
|
+ "Referenced: %8lu kB\n"
|
|
|
|
+ "Anonymous: %8lu kB\n"
|
|
|
|
+ "LazyFree: %8lu kB\n"
|
|
|
|
+ "AnonHugePages: %8lu kB\n"
|
|
|
|
+ "ShmemPmdMapped: %8lu kB\n"
|
|
|
|
+ "Shared_Hugetlb: %8lu kB\n"
|
|
|
|
+ "Private_Hugetlb: %7lu kB\n"
|
|
|
|
+ "Swap: %8lu kB\n"
|
|
|
|
+ "SwapPss: %8lu kB\n"
|
|
|
|
+ "Locked: %8lu kB\n",
|
|
|
|
+ mss->resident >> 10,
|
|
|
|
+ (unsigned long)(mss->pss >> (10 + PSS_SHIFT)),
|
|
|
|
+ mss->shared_clean >> 10,
|
|
|
|
+ mss->shared_dirty >> 10,
|
|
|
|
+ mss->private_clean >> 10,
|
|
|
|
+ mss->private_dirty >> 10,
|
|
|
|
+ mss->referenced >> 10,
|
|
|
|
+ mss->anonymous >> 10,
|
|
|
|
+ mss->lazyfree >> 10,
|
|
|
|
+ mss->anonymous_thp >> 10,
|
|
|
|
+ mss->shmem_thp >> 10,
|
|
|
|
+ mss->shared_hugetlb >> 10,
|
|
|
|
+ mss->private_hugetlb >> 10,
|
|
|
|
+ mss->swap >> 10,
|
|
|
|
+ (unsigned long)(mss->swap_pss >> (10 + PSS_SHIFT)),
|
|
|
|
+ (unsigned long)(mss->pss >> (10 + PSS_SHIFT)));
|
|
|
|
+
|
|
|
|
+ if (!rollup_mode) {
|
|
|
|
+ arch_show_smap(m, vma);
|
|
|
|
+ show_smap_vma_flags(m, vma);
|
|
|
|
+ }
|
|
m_cache_vma(m, vma);
|
|
m_cache_vma(m, vma);
|
|
- return 0;
|
|
|
|
|
|
+ return ret;
|
|
}
|
|
}
|
|
|
|
|
|
static int show_pid_smap(struct seq_file *m, void *v)
|
|
static int show_pid_smap(struct seq_file *m, void *v)
|
|
@@ -837,6 +883,25 @@ static int pid_smaps_open(struct inode *inode, struct file *file)
|
|
return do_maps_open(inode, file, &proc_pid_smaps_op);
|
|
return do_maps_open(inode, file, &proc_pid_smaps_op);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static int pid_smaps_rollup_open(struct inode *inode, struct file *file)
|
|
|
|
+{
|
|
|
|
+ struct seq_file *seq;
|
|
|
|
+ struct proc_maps_private *priv;
|
|
|
|
+ int ret = do_maps_open(inode, file, &proc_pid_smaps_op);
|
|
|
|
+
|
|
|
|
+ if (ret < 0)
|
|
|
|
+ return ret;
|
|
|
|
+ seq = file->private_data;
|
|
|
|
+ priv = seq->private;
|
|
|
|
+ priv->rollup = kzalloc(sizeof(*priv->rollup), GFP_KERNEL);
|
|
|
|
+ if (!priv->rollup) {
|
|
|
|
+ proc_map_release(inode, file);
|
|
|
|
+ return -ENOMEM;
|
|
|
|
+ }
|
|
|
|
+ priv->rollup->first = true;
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
static int tid_smaps_open(struct inode *inode, struct file *file)
|
|
static int tid_smaps_open(struct inode *inode, struct file *file)
|
|
{
|
|
{
|
|
return do_maps_open(inode, file, &proc_tid_smaps_op);
|
|
return do_maps_open(inode, file, &proc_tid_smaps_op);
|
|
@@ -849,6 +914,13 @@ const struct file_operations proc_pid_smaps_operations = {
|
|
.release = proc_map_release,
|
|
.release = proc_map_release,
|
|
};
|
|
};
|
|
|
|
|
|
|
|
+const struct file_operations proc_pid_smaps_rollup_operations = {
|
|
|
|
+ .open = pid_smaps_rollup_open,
|
|
|
|
+ .read = seq_read,
|
|
|
|
+ .llseek = seq_lseek,
|
|
|
|
+ .release = proc_map_release,
|
|
|
|
+};
|
|
|
|
+
|
|
const struct file_operations proc_tid_smaps_operations = {
|
|
const struct file_operations proc_tid_smaps_operations = {
|
|
.open = tid_smaps_open,
|
|
.open = tid_smaps_open,
|
|
.read = seq_read,
|
|
.read = seq_read,
|