Merge branch 'for-linus' of git://one.firstfloor.org/home/andi/git/linux-2.6
[linux-2.6] / fs / proc / task_nommu.c
1
2 #include <linux/mm.h>
3 #include <linux/file.h>
4 #include <linux/mount.h>
5 #include <linux/seq_file.h>
6 #include "internal.h"
7
8 /*
9  * Logic: we've got two memory sums for each process, "shared", and
10  * "non-shared". Shared memory may get counted more then once, for
11  * each process that owns it. Non-shared memory is counted
12  * accurately.
13  */
14 char *task_mem(struct mm_struct *mm, char *buffer)
15 {
16         struct vm_list_struct *vml;
17         unsigned long bytes = 0, sbytes = 0, slack = 0;
18         
19         down_read(&mm->mmap_sem);
20         for (vml = mm->context.vmlist; vml; vml = vml->next) {
21                 if (!vml->vma)
22                         continue;
23
24                 bytes += kobjsize(vml);
25                 if (atomic_read(&mm->mm_count) > 1 ||
26                     atomic_read(&vml->vma->vm_usage) > 1
27                     ) {
28                         sbytes += kobjsize((void *) vml->vma->vm_start);
29                         sbytes += kobjsize(vml->vma);
30                 } else {
31                         bytes += kobjsize((void *) vml->vma->vm_start);
32                         bytes += kobjsize(vml->vma);
33                         slack += kobjsize((void *) vml->vma->vm_start) -
34                                 (vml->vma->vm_end - vml->vma->vm_start);
35                 }
36         }
37
38         if (atomic_read(&mm->mm_count) > 1)
39                 sbytes += kobjsize(mm);
40         else
41                 bytes += kobjsize(mm);
42         
43         if (current->fs && atomic_read(&current->fs->count) > 1)
44                 sbytes += kobjsize(current->fs);
45         else
46                 bytes += kobjsize(current->fs);
47
48         if (current->files && atomic_read(&current->files->count) > 1)
49                 sbytes += kobjsize(current->files);
50         else
51                 bytes += kobjsize(current->files);
52
53         if (current->sighand && atomic_read(&current->sighand->count) > 1)
54                 sbytes += kobjsize(current->sighand);
55         else
56                 bytes += kobjsize(current->sighand);
57
58         bytes += kobjsize(current); /* includes kernel stack */
59
60         buffer += sprintf(buffer,
61                 "Mem:\t%8lu bytes\n"
62                 "Slack:\t%8lu bytes\n"
63                 "Shared:\t%8lu bytes\n",
64                 bytes, slack, sbytes);
65
66         up_read(&mm->mmap_sem);
67         return buffer;
68 }
69
70 unsigned long task_vsize(struct mm_struct *mm)
71 {
72         struct vm_list_struct *tbp;
73         unsigned long vsize = 0;
74
75         down_read(&mm->mmap_sem);
76         for (tbp = mm->context.vmlist; tbp; tbp = tbp->next) {
77                 if (tbp->vma)
78                         vsize += kobjsize((void *) tbp->vma->vm_start);
79         }
80         up_read(&mm->mmap_sem);
81         return vsize;
82 }
83
84 int task_statm(struct mm_struct *mm, int *shared, int *text,
85                int *data, int *resident)
86 {
87         struct vm_list_struct *tbp;
88         int size = kobjsize(mm);
89
90         down_read(&mm->mmap_sem);
91         for (tbp = mm->context.vmlist; tbp; tbp = tbp->next) {
92                 size += kobjsize(tbp);
93                 if (tbp->vma) {
94                         size += kobjsize(tbp->vma);
95                         size += kobjsize((void *) tbp->vma->vm_start);
96                 }
97         }
98
99         size += (*text = mm->end_code - mm->start_code);
100         size += (*data = mm->start_stack - mm->start_data);
101         up_read(&mm->mmap_sem);
102         *resident = size;
103         return size;
104 }
105
106 int proc_exe_link(struct inode *inode, struct dentry **dentry, struct vfsmount **mnt)
107 {
108         struct vm_list_struct *vml;
109         struct vm_area_struct *vma;
110         struct task_struct *task = get_proc_task(inode);
111         struct mm_struct *mm = get_task_mm(task);
112         int result = -ENOENT;
113
114         if (!mm)
115                 goto out;
116         down_read(&mm->mmap_sem);
117
118         vml = mm->context.vmlist;
119         vma = NULL;
120         while (vml) {
121                 if ((vml->vma->vm_flags & VM_EXECUTABLE) && vml->vma->vm_file) {
122                         vma = vml->vma;
123                         break;
124                 }
125                 vml = vml->next;
126         }
127
128         if (vma) {
129                 *mnt = mntget(vma->vm_file->f_path.mnt);
130                 *dentry = dget(vma->vm_file->f_path.dentry);
131                 result = 0;
132         }
133
134         up_read(&mm->mmap_sem);
135         mmput(mm);
136 out:
137         return result;
138 }
139
140 /*
141  * display mapping lines for a particular process's /proc/pid/maps
142  */
143 static int show_map(struct seq_file *m, void *_vml)
144 {
145         struct vm_list_struct *vml = _vml;
146         return nommu_vma_show(m, vml->vma);
147 }
148
149 static void *m_start(struct seq_file *m, loff_t *pos)
150 {
151         struct proc_maps_private *priv = m->private;
152         struct vm_list_struct *vml;
153         struct mm_struct *mm;
154         loff_t n = *pos;
155
156         /* pin the task and mm whilst we play with them */
157         priv->task = get_pid_task(priv->pid, PIDTYPE_PID);
158         if (!priv->task)
159                 return NULL;
160
161         mm = get_task_mm(priv->task);
162         if (!mm) {
163                 put_task_struct(priv->task);
164                 priv->task = NULL;
165                 return NULL;
166         }
167
168         down_read(&mm->mmap_sem);
169
170         /* start from the Nth VMA */
171         for (vml = mm->context.vmlist; vml; vml = vml->next)
172                 if (n-- == 0)
173                         return vml;
174         return NULL;
175 }
176
177 static void m_stop(struct seq_file *m, void *_vml)
178 {
179         struct proc_maps_private *priv = m->private;
180
181         if (priv->task) {
182                 struct mm_struct *mm = priv->task->mm;
183                 up_read(&mm->mmap_sem);
184                 mmput(mm);
185                 put_task_struct(priv->task);
186         }
187 }
188
189 static void *m_next(struct seq_file *m, void *_vml, loff_t *pos)
190 {
191         struct vm_list_struct *vml = _vml;
192
193         (*pos)++;
194         return vml ? vml->next : NULL;
195 }
196
197 static struct seq_operations proc_pid_maps_ops = {
198         .start  = m_start,
199         .next   = m_next,
200         .stop   = m_stop,
201         .show   = show_map
202 };
203
204 static int maps_open(struct inode *inode, struct file *file)
205 {
206         struct proc_maps_private *priv;
207         int ret = -ENOMEM;
208
209         priv = kzalloc(sizeof(*priv), GFP_KERNEL);
210         if (priv) {
211                 priv->pid = proc_pid(inode);
212                 ret = seq_open(file, &proc_pid_maps_ops);
213                 if (!ret) {
214                         struct seq_file *m = file->private_data;
215                         m->private = priv;
216                 } else {
217                         kfree(priv);
218                 }
219         }
220         return ret;
221 }
222
223 const struct file_operations proc_maps_operations = {
224         .open           = maps_open,
225         .read           = seq_read,
226         .llseek         = seq_lseek,
227         .release        = seq_release_private,
228 };
229