blob: b2142e7c3e6bab16cf87d022e5acb536adaeb235 [file] [log] [blame]
From 983dd2810c37f2d24adc2c7057eb15f72d21b377 Mon Sep 17 00:00:00 2001
From: Sonny Rao <sonnyrao@chromium.org>
Date: Tue, 16 Jul 2013 13:06:45 -0700
Subject: [PATCH] CHROMIUM: mm: implement /proc/<pid>/totmaps
This is based on earlier work by Thiago Goncales. It implements a new
per process proc file which summarizes the contents of the smaps file
but doesn't display any addresses. It gives more detailed information
than statm like the PSS (proprotional set size). It differs from the
original implementation in that it doesn't use the full blown set of
seq operations, uses a different termination condition, and doesn't
displayed "Locked" as that was broken on the original implemenation.
BUG=chromium:258160
TEST=manual, cat /proc/self/totmaps and verify information is present
Change-Id: I6f631162709efc075897f366dc11a76abfa09cd1
Signed-off-by: Sonny Rao <sonnyrao@chromium.org>
Reviewed-on: https://gerrit.chromium.org/gerrit/62217
[benzh: 3.14 rebase. Resolved trivial conflicts]
[bfreed: 3.18 rebase. Resolved compile failure]
Signed-off-by: Ben Zhang <benzh@chromium.org>
Signed-off-by: Bryan Freed <bfreed@chromium.org>
[rebase44(filbranden): Use walk_page_vma() and remove the assignment of
mss.vma which is no longer necessary after upstream commit
14eb6fdd4204d2 ("smaps: remove mem_size_stats->vma and use
walk_page_vma()") that dropped that field.
Squashed these commits together:
- CHROMIUM: mm: implement /proc/<pid>/totmaps
- CHROMIUM: procfs: fix leak in totmaps_release()
]
Signed-off-by: Filipe Brandenburger <filbranden@chromium.org>
[rebase419(groeck): Context conflicts]
Signed-off-by: Guenter Roeck <groeck@chromium.org>
[rebase54(groeck): walk_page() parameter changes]
Signed-off-by: Guenter Roeck <groeck@chromium.org>
[rebase510(groeck): mmap locking changes]
Signed-off-by: Guenter Roeck <groeck@chromium.org>
[rebase61(tzungbi):
Squashed:
FIXUP: CHROMIUM: mm: implement /proc/<pid>/totmaps
]
Signed-off-by: Tzung-Bi Shih <tzungbi@chromium.org>
---
fs/proc/base.c | 1 +
fs/proc/internal.h | 6 +++
fs/proc/task_mmu.c | 123 +++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 130 insertions(+)
diff --git a/fs/proc/base.c b/fs/proc/base.c
index ffd54617c35478e92a9f6bef67013e16e6cd3183..f9c701f149df653ef37f81b9a7fbeb2dd0437f8f 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -3284,6 +3284,7 @@ static const struct pid_entry tgid_base_stuff[] = {
REG("smaps", S_IRUGO, proc_pid_smaps_operations),
REG("smaps_rollup", S_IRUGO, proc_pid_smaps_rollup_operations),
REG("pagemap", S_IRUSR, proc_pagemap_operations),
+ REG("totmaps", S_IRUGO, proc_totmaps_operations),
#endif
#ifdef CONFIG_SECURITY
DIR("attr", S_IRUGO|S_IXUGO, proc_attr_dir_inode_operations, proc_attr_dir_operations),
diff --git a/fs/proc/internal.h b/fs/proc/internal.h
index 9a8f32f21ff569d0dc40e1d7c31b63b9aea293bc..d16ec48623078f83efa59d941bf8acca7d5098c3 100644
--- a/fs/proc/internal.h
+++ b/fs/proc/internal.h
@@ -95,6 +95,9 @@ union proc_op {
const char *lsm;
};
+
+extern const struct file_operations proc_totmaps_operations;
+
struct proc_inode {
struct pid *pid;
unsigned int fd;
@@ -290,6 +293,9 @@ struct proc_maps_private {
struct task_struct *task;
struct mm_struct *mm;
struct vma_iterator iter;
+#ifdef CONFIG_MMU
+ struct mem_size_stats *mss;
+#endif
#ifdef CONFIG_NUMA
struct mempolicy *task_mempolicy;
#endif
diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c
index 3dd5be96691b4cc234454353ec1b8a324760e0c2..ee48c9d106895ef1f64974a8dfebe5d75c4ab0d2 100644
--- a/fs/proc/task_mmu.c
+++ b/fs/proc/task_mmu.c
@@ -874,6 +874,78 @@ static int show_smap(struct seq_file *m, void *v)
return 0;
}
+static void add_smaps_sum(struct mem_size_stats *mss,
+ struct mem_size_stats *mss_sum)
+{
+ mss_sum->resident += mss->resident;
+ mss_sum->pss += mss->pss;
+ mss_sum->shared_clean += mss->shared_clean;
+ mss_sum->shared_dirty += mss->shared_dirty;
+ mss_sum->private_clean += mss->private_clean;
+ mss_sum->private_dirty += mss->private_dirty;
+ mss_sum->referenced += mss->referenced;
+ mss_sum->anonymous += mss->anonymous;
+ mss_sum->anonymous_thp += mss->anonymous_thp;
+ mss_sum->swap += mss->swap;
+}
+
+static int totmaps_proc_show(struct seq_file *m, void *data)
+{
+ struct proc_maps_private *priv = m->private;
+ struct mm_struct *mm;
+ struct vm_area_struct *vma;
+ struct mem_size_stats *mss_sum = priv->mss;
+ struct vma_iterator vmi;
+
+ /* reference to priv->task already taken */
+ /* but need to get the mm here because */
+ /* task could be in the process of exiting */
+ mm = get_task_mm(priv->task);
+ if (!mm || IS_ERR(mm))
+ return -EINVAL;
+
+ mmap_read_lock(mm);
+ hold_task_mempolicy(priv);
+
+ vma_iter_init(&vmi, mm, 0);
+ for_each_vma(vmi, vma) {
+ struct mem_size_stats mss;
+
+ if (vma->vm_mm && !is_vm_hugetlb_page(vma)) {
+ memset(&mss, 0, sizeof(mss));
+ walk_page_vma(vma, &smaps_walk_ops, &mss);
+ add_smaps_sum(&mss, mss_sum);
+ }
+ }
+ 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"
+ "AnonHugePages: %8lu kB\n"
+ "Swap: %8lu kB\n",
+ mss_sum->resident >> 10,
+ (unsigned long)(mss_sum->pss >> (10 + PSS_SHIFT)),
+ mss_sum->shared_clean >> 10,
+ mss_sum->shared_dirty >> 10,
+ mss_sum->private_clean >> 10,
+ mss_sum->private_dirty >> 10,
+ mss_sum->referenced >> 10,
+ mss_sum->anonymous >> 10,
+ mss_sum->anonymous_thp >> 10,
+ mss_sum->swap >> 10);
+
+ release_task_mempolicy(priv);
+ mmap_read_unlock(mm);
+ mmput(mm);
+
+ return 0;
+}
+
static int show_smaps_rollup(struct seq_file *m, void *v)
{
struct proc_maps_private *priv = m->private;
@@ -1047,6 +1119,50 @@ static int smaps_rollup_release(struct inode *inode, struct file *file)
return single_release(inode, file);
}
+static int totmaps_open(struct inode *inode, struct file *file)
+{
+ struct proc_maps_private *priv;
+ int ret = -ENOMEM;
+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+ if (priv) {
+ priv->mss = kzalloc(sizeof(*priv->mss), GFP_KERNEL);
+ if (!priv->mss)
+ return -ENOMEM;
+
+ /* we need to grab references to the task_struct */
+ /* at open time, because there's a potential information */
+ /* leak where the totmaps file is opened and held open */
+ /* while the underlying pid to task mapping changes */
+ /* underneath it */
+ priv->task = get_pid_task(proc_pid(inode), PIDTYPE_PID);
+ if (!priv->task) {
+ kfree(priv->mss);
+ kfree(priv);
+ return -ESRCH;
+ }
+
+ ret = single_open(file, totmaps_proc_show, priv);
+ if (ret) {
+ put_task_struct(priv->task);
+ kfree(priv->mss);
+ kfree(priv);
+ }
+ }
+ return ret;
+}
+
+static int totmaps_release(struct inode *inode, struct file *file)
+{
+ struct seq_file *m = file->private_data;
+ struct proc_maps_private *priv = m->private;
+
+ put_task_struct(priv->task);
+ kfree(priv->mss);
+ kfree(priv);
+ m->private = NULL;
+ return single_release(inode, file);
+}
+
const struct file_operations proc_pid_smaps_operations = {
.open = pid_smaps_open,
.read = seq_read,
@@ -1061,6 +1177,13 @@ const struct file_operations proc_pid_smaps_rollup_operations = {
.release = smaps_rollup_release,
};
+const struct file_operations proc_totmaps_operations = {
+ .open = totmaps_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = totmaps_release,
+};
+
enum clear_refs_types {
CLEAR_REFS_ALL = 1,
CLEAR_REFS_ANON,
--
2.34.1