aboutsummaryrefslogtreecommitdiffstats
path: root/fs/proc/base.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/proc/base.c')
-rw-r--r--fs/proc/base.c159
1 files changed, 115 insertions, 44 deletions
diff --git a/fs/proc/base.c b/fs/proc/base.c
index 491f2d9f89ac..84751f3f52d5 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -11,6 +11,40 @@
11 * go into icache. We cache the reference to task_struct upon lookup too. 11 * go into icache. We cache the reference to task_struct upon lookup too.
12 * Eventually it should become a filesystem in its own. We don't use the 12 * Eventually it should become a filesystem in its own. We don't use the
13 * rest of procfs anymore. 13 * rest of procfs anymore.
14 *
15 *
16 * Changelog:
17 * 17-Jan-2005
18 * Allan Bezerra
19 * Bruna Moreira <bruna.moreira@indt.org.br>
20 * Edjard Mota <edjard.mota@indt.org.br>
21 * Ilias Biris <ilias.biris@indt.org.br>
22 * Mauricio Lin <mauricio.lin@indt.org.br>
23 *
24 * Embedded Linux Lab - 10LE Instituto Nokia de Tecnologia - INdT
25 *
26 * A new process specific entry (smaps) included in /proc. It shows the
27 * size of rss for each memory area. The maps entry lacks information
28 * about physical memory size (rss) for each mapped file, i.e.,
29 * rss information for executables and library files.
30 * This additional information is useful for any tools that need to know
31 * about physical memory consumption for a process specific library.
32 *
33 * Changelog:
34 * 21-Feb-2005
35 * Embedded Linux Lab - 10LE Instituto Nokia de Tecnologia - INdT
36 * Pud inclusion in the page table walking.
37 *
38 * ChangeLog:
39 * 10-Mar-2005
40 * 10LE Instituto Nokia de Tecnologia - INdT:
41 * A better way to walks through the page table as suggested by Hugh Dickins.
42 *
43 * Simo Piiroinen <simo.piiroinen@nokia.com>:
44 * Smaps information related to shared, private, clean and dirty pages.
45 *
46 * Paul Mundt <paul.mundt@nokia.com>:
47 * Overall revision about smaps.
14 */ 48 */
15 49
16#include <asm/uaccess.h> 50#include <asm/uaccess.h>
@@ -65,8 +99,10 @@ enum pid_directory_inos {
65 PROC_TGID_STAT, 99 PROC_TGID_STAT,
66 PROC_TGID_STATM, 100 PROC_TGID_STATM,
67 PROC_TGID_MAPS, 101 PROC_TGID_MAPS,
102 PROC_TGID_NUMA_MAPS,
68 PROC_TGID_MOUNTS, 103 PROC_TGID_MOUNTS,
69 PROC_TGID_WCHAN, 104 PROC_TGID_WCHAN,
105 PROC_TGID_SMAPS,
70#ifdef CONFIG_SCHEDSTATS 106#ifdef CONFIG_SCHEDSTATS
71 PROC_TGID_SCHEDSTAT, 107 PROC_TGID_SCHEDSTAT,
72#endif 108#endif
@@ -83,7 +119,6 @@ enum pid_directory_inos {
83#ifdef CONFIG_AUDITSYSCALL 119#ifdef CONFIG_AUDITSYSCALL
84 PROC_TGID_LOGINUID, 120 PROC_TGID_LOGINUID,
85#endif 121#endif
86 PROC_TGID_FD_DIR,
87 PROC_TGID_OOM_SCORE, 122 PROC_TGID_OOM_SCORE,
88 PROC_TGID_OOM_ADJUST, 123 PROC_TGID_OOM_ADJUST,
89 PROC_TID_INO, 124 PROC_TID_INO,
@@ -102,8 +137,10 @@ enum pid_directory_inos {
102 PROC_TID_STAT, 137 PROC_TID_STAT,
103 PROC_TID_STATM, 138 PROC_TID_STATM,
104 PROC_TID_MAPS, 139 PROC_TID_MAPS,
140 PROC_TID_NUMA_MAPS,
105 PROC_TID_MOUNTS, 141 PROC_TID_MOUNTS,
106 PROC_TID_WCHAN, 142 PROC_TID_WCHAN,
143 PROC_TID_SMAPS,
107#ifdef CONFIG_SCHEDSTATS 144#ifdef CONFIG_SCHEDSTATS
108 PROC_TID_SCHEDSTAT, 145 PROC_TID_SCHEDSTAT,
109#endif 146#endif
@@ -120,9 +157,11 @@ enum pid_directory_inos {
120#ifdef CONFIG_AUDITSYSCALL 157#ifdef CONFIG_AUDITSYSCALL
121 PROC_TID_LOGINUID, 158 PROC_TID_LOGINUID,
122#endif 159#endif
123 PROC_TID_FD_DIR = 0x8000, /* 0x8000-0xffff */
124 PROC_TID_OOM_SCORE, 160 PROC_TID_OOM_SCORE,
125 PROC_TID_OOM_ADJUST, 161 PROC_TID_OOM_ADJUST,
162
163 /* Add new entries before this */
164 PROC_TID_FD_DIR = 0x8000, /* 0x8000-0xffff */
126}; 165};
127 166
128struct pid_entry { 167struct pid_entry {
@@ -144,6 +183,9 @@ static struct pid_entry tgid_base_stuff[] = {
144 E(PROC_TGID_STAT, "stat", S_IFREG|S_IRUGO), 183 E(PROC_TGID_STAT, "stat", S_IFREG|S_IRUGO),
145 E(PROC_TGID_STATM, "statm", S_IFREG|S_IRUGO), 184 E(PROC_TGID_STATM, "statm", S_IFREG|S_IRUGO),
146 E(PROC_TGID_MAPS, "maps", S_IFREG|S_IRUGO), 185 E(PROC_TGID_MAPS, "maps", S_IFREG|S_IRUGO),
186#ifdef CONFIG_NUMA
187 E(PROC_TGID_NUMA_MAPS, "numa_maps", S_IFREG|S_IRUGO),
188#endif
147 E(PROC_TGID_MEM, "mem", S_IFREG|S_IRUSR|S_IWUSR), 189 E(PROC_TGID_MEM, "mem", S_IFREG|S_IRUSR|S_IWUSR),
148#ifdef CONFIG_SECCOMP 190#ifdef CONFIG_SECCOMP
149 E(PROC_TGID_SECCOMP, "seccomp", S_IFREG|S_IRUSR|S_IWUSR), 191 E(PROC_TGID_SECCOMP, "seccomp", S_IFREG|S_IRUSR|S_IWUSR),
@@ -152,6 +194,7 @@ static struct pid_entry tgid_base_stuff[] = {
152 E(PROC_TGID_ROOT, "root", S_IFLNK|S_IRWXUGO), 194 E(PROC_TGID_ROOT, "root", S_IFLNK|S_IRWXUGO),
153 E(PROC_TGID_EXE, "exe", S_IFLNK|S_IRWXUGO), 195 E(PROC_TGID_EXE, "exe", S_IFLNK|S_IRWXUGO),
154 E(PROC_TGID_MOUNTS, "mounts", S_IFREG|S_IRUGO), 196 E(PROC_TGID_MOUNTS, "mounts", S_IFREG|S_IRUGO),
197 E(PROC_TGID_SMAPS, "smaps", S_IFREG|S_IRUGO),
155#ifdef CONFIG_SECURITY 198#ifdef CONFIG_SECURITY
156 E(PROC_TGID_ATTR, "attr", S_IFDIR|S_IRUGO|S_IXUGO), 199 E(PROC_TGID_ATTR, "attr", S_IFDIR|S_IRUGO|S_IXUGO),
157#endif 200#endif
@@ -180,6 +223,9 @@ static struct pid_entry tid_base_stuff[] = {
180 E(PROC_TID_STAT, "stat", S_IFREG|S_IRUGO), 223 E(PROC_TID_STAT, "stat", S_IFREG|S_IRUGO),
181 E(PROC_TID_STATM, "statm", S_IFREG|S_IRUGO), 224 E(PROC_TID_STATM, "statm", S_IFREG|S_IRUGO),
182 E(PROC_TID_MAPS, "maps", S_IFREG|S_IRUGO), 225 E(PROC_TID_MAPS, "maps", S_IFREG|S_IRUGO),
226#ifdef CONFIG_NUMA
227 E(PROC_TID_NUMA_MAPS, "numa_maps", S_IFREG|S_IRUGO),
228#endif
183 E(PROC_TID_MEM, "mem", S_IFREG|S_IRUSR|S_IWUSR), 229 E(PROC_TID_MEM, "mem", S_IFREG|S_IRUSR|S_IWUSR),
184#ifdef CONFIG_SECCOMP 230#ifdef CONFIG_SECCOMP
185 E(PROC_TID_SECCOMP, "seccomp", S_IFREG|S_IRUSR|S_IWUSR), 231 E(PROC_TID_SECCOMP, "seccomp", S_IFREG|S_IRUSR|S_IWUSR),
@@ -188,6 +234,7 @@ static struct pid_entry tid_base_stuff[] = {
188 E(PROC_TID_ROOT, "root", S_IFLNK|S_IRWXUGO), 234 E(PROC_TID_ROOT, "root", S_IFLNK|S_IRWXUGO),
189 E(PROC_TID_EXE, "exe", S_IFLNK|S_IRWXUGO), 235 E(PROC_TID_EXE, "exe", S_IFLNK|S_IRWXUGO),
190 E(PROC_TID_MOUNTS, "mounts", S_IFREG|S_IRUGO), 236 E(PROC_TID_MOUNTS, "mounts", S_IFREG|S_IRUGO),
237 E(PROC_TID_SMAPS, "smaps", S_IFREG|S_IRUGO),
191#ifdef CONFIG_SECURITY 238#ifdef CONFIG_SECURITY
192 E(PROC_TID_ATTR, "attr", S_IFDIR|S_IRUGO|S_IXUGO), 239 E(PROC_TID_ATTR, "attr", S_IFDIR|S_IRUGO|S_IXUGO),
193#endif 240#endif
@@ -251,15 +298,21 @@ static int proc_fd_link(struct inode *inode, struct dentry **dentry, struct vfsm
251 return -ENOENT; 298 return -ENOENT;
252} 299}
253 300
254static int proc_cwd_link(struct inode *inode, struct dentry **dentry, struct vfsmount **mnt) 301static struct fs_struct *get_fs_struct(struct task_struct *task)
255{ 302{
256 struct fs_struct *fs; 303 struct fs_struct *fs;
257 int result = -ENOENT; 304 task_lock(task);
258 task_lock(proc_task(inode)); 305 fs = task->fs;
259 fs = proc_task(inode)->fs;
260 if(fs) 306 if(fs)
261 atomic_inc(&fs->count); 307 atomic_inc(&fs->count);
262 task_unlock(proc_task(inode)); 308 task_unlock(task);
309 return fs;
310}
311
312static int proc_cwd_link(struct inode *inode, struct dentry **dentry, struct vfsmount **mnt)
313{
314 struct fs_struct *fs = get_fs_struct(proc_task(inode));
315 int result = -ENOENT;
263 if (fs) { 316 if (fs) {
264 read_lock(&fs->lock); 317 read_lock(&fs->lock);
265 *mnt = mntget(fs->pwdmnt); 318 *mnt = mntget(fs->pwdmnt);
@@ -273,13 +326,8 @@ static int proc_cwd_link(struct inode *inode, struct dentry **dentry, struct vfs
273 326
274static int proc_root_link(struct inode *inode, struct dentry **dentry, struct vfsmount **mnt) 327static int proc_root_link(struct inode *inode, struct dentry **dentry, struct vfsmount **mnt)
275{ 328{
276 struct fs_struct *fs; 329 struct fs_struct *fs = get_fs_struct(proc_task(inode));
277 int result = -ENOENT; 330 int result = -ENOENT;
278 task_lock(proc_task(inode));
279 fs = proc_task(inode)->fs;
280 if(fs)
281 atomic_inc(&fs->count);
282 task_unlock(proc_task(inode));
283 if (fs) { 331 if (fs) {
284 read_lock(&fs->lock); 332 read_lock(&fs->lock);
285 *mnt = mntget(fs->rootmnt); 333 *mnt = mntget(fs->rootmnt);
@@ -298,33 +346,6 @@ static int proc_root_link(struct inode *inode, struct dentry **dentry, struct vf
298 (task->state == TASK_STOPPED || task->state == TASK_TRACED) && \ 346 (task->state == TASK_STOPPED || task->state == TASK_TRACED) && \
299 security_ptrace(current,task) == 0)) 347 security_ptrace(current,task) == 0))
300 348
301static int may_ptrace_attach(struct task_struct *task)
302{
303 int retval = 0;
304
305 task_lock(task);
306
307 if (!task->mm)
308 goto out;
309 if (((current->uid != task->euid) ||
310 (current->uid != task->suid) ||
311 (current->uid != task->uid) ||
312 (current->gid != task->egid) ||
313 (current->gid != task->sgid) ||
314 (current->gid != task->gid)) && !capable(CAP_SYS_PTRACE))
315 goto out;
316 rmb();
317 if (task->mm->dumpable != 1 && !capable(CAP_SYS_PTRACE))
318 goto out;
319 if (security_ptrace(current, task))
320 goto out;
321
322 retval = 1;
323out:
324 task_unlock(task);
325 return retval;
326}
327
328static int proc_pid_environ(struct task_struct *task, char * buffer) 349static int proc_pid_environ(struct task_struct *task, char * buffer)
329{ 350{
330 int res = 0; 351 int res = 0;
@@ -334,7 +355,7 @@ static int proc_pid_environ(struct task_struct *task, char * buffer)
334 if (len > PAGE_SIZE) 355 if (len > PAGE_SIZE)
335 len = PAGE_SIZE; 356 len = PAGE_SIZE;
336 res = access_process_vm(task, mm->env_start, buffer, len, 0); 357 res = access_process_vm(task, mm->env_start, buffer, len, 0);
337 if (!may_ptrace_attach(task)) 358 if (!ptrace_may_attach(task))
338 res = -ESRCH; 359 res = -ESRCH;
339 mmput(mm); 360 mmput(mm);
340 } 361 }
@@ -515,6 +536,46 @@ static struct file_operations proc_maps_operations = {
515 .release = seq_release, 536 .release = seq_release,
516}; 537};
517 538
539#ifdef CONFIG_NUMA
540extern struct seq_operations proc_pid_numa_maps_op;
541static int numa_maps_open(struct inode *inode, struct file *file)
542{
543 struct task_struct *task = proc_task(inode);
544 int ret = seq_open(file, &proc_pid_numa_maps_op);
545 if (!ret) {
546 struct seq_file *m = file->private_data;
547 m->private = task;
548 }
549 return ret;
550}
551
552static struct file_operations proc_numa_maps_operations = {
553 .open = numa_maps_open,
554 .read = seq_read,
555 .llseek = seq_lseek,
556 .release = seq_release,
557};
558#endif
559
560extern struct seq_operations proc_pid_smaps_op;
561static int smaps_open(struct inode *inode, struct file *file)
562{
563 struct task_struct *task = proc_task(inode);
564 int ret = seq_open(file, &proc_pid_smaps_op);
565 if (!ret) {
566 struct seq_file *m = file->private_data;
567 m->private = task;
568 }
569 return ret;
570}
571
572static struct file_operations proc_smaps_operations = {
573 .open = smaps_open,
574 .read = seq_read,
575 .llseek = seq_lseek,
576 .release = seq_release,
577};
578
518extern struct seq_operations mounts_op; 579extern struct seq_operations mounts_op;
519static int mounts_open(struct inode *inode, struct file *file) 580static int mounts_open(struct inode *inode, struct file *file)
520{ 581{
@@ -597,7 +658,7 @@ static ssize_t mem_read(struct file * file, char __user * buf,
597 int ret = -ESRCH; 658 int ret = -ESRCH;
598 struct mm_struct *mm; 659 struct mm_struct *mm;
599 660
600 if (!MAY_PTRACE(task) || !may_ptrace_attach(task)) 661 if (!MAY_PTRACE(task) || !ptrace_may_attach(task))
601 goto out; 662 goto out;
602 663
603 ret = -ENOMEM; 664 ret = -ENOMEM;
@@ -623,7 +684,7 @@ static ssize_t mem_read(struct file * file, char __user * buf,
623 684
624 this_len = (count > PAGE_SIZE) ? PAGE_SIZE : count; 685 this_len = (count > PAGE_SIZE) ? PAGE_SIZE : count;
625 retval = access_process_vm(task, src, page, this_len, 0); 686 retval = access_process_vm(task, src, page, this_len, 0);
626 if (!retval || !MAY_PTRACE(task) || !may_ptrace_attach(task)) { 687 if (!retval || !MAY_PTRACE(task) || !ptrace_may_attach(task)) {
627 if (!ret) 688 if (!ret)
628 ret = -EIO; 689 ret = -EIO;
629 break; 690 break;
@@ -661,7 +722,7 @@ static ssize_t mem_write(struct file * file, const char * buf,
661 struct task_struct *task = proc_task(file->f_dentry->d_inode); 722 struct task_struct *task = proc_task(file->f_dentry->d_inode);
662 unsigned long dst = *ppos; 723 unsigned long dst = *ppos;
663 724
664 if (!MAY_PTRACE(task) || !may_ptrace_attach(task)) 725 if (!MAY_PTRACE(task) || !ptrace_may_attach(task))
665 return -ESRCH; 726 return -ESRCH;
666 727
667 page = (char *)__get_free_page(GFP_USER); 728 page = (char *)__get_free_page(GFP_USER);
@@ -1524,6 +1585,12 @@ static struct dentry *proc_pident_lookup(struct inode *dir,
1524 case PROC_TGID_MAPS: 1585 case PROC_TGID_MAPS:
1525 inode->i_fop = &proc_maps_operations; 1586 inode->i_fop = &proc_maps_operations;
1526 break; 1587 break;
1588#ifdef CONFIG_NUMA
1589 case PROC_TID_NUMA_MAPS:
1590 case PROC_TGID_NUMA_MAPS:
1591 inode->i_fop = &proc_numa_maps_operations;
1592 break;
1593#endif
1527 case PROC_TID_MEM: 1594 case PROC_TID_MEM:
1528 case PROC_TGID_MEM: 1595 case PROC_TGID_MEM:
1529 inode->i_op = &proc_mem_inode_operations; 1596 inode->i_op = &proc_mem_inode_operations;
@@ -1539,6 +1606,10 @@ static struct dentry *proc_pident_lookup(struct inode *dir,
1539 case PROC_TGID_MOUNTS: 1606 case PROC_TGID_MOUNTS:
1540 inode->i_fop = &proc_mounts_operations; 1607 inode->i_fop = &proc_mounts_operations;
1541 break; 1608 break;
1609 case PROC_TID_SMAPS:
1610 case PROC_TGID_SMAPS:
1611 inode->i_fop = &proc_smaps_operations;
1612 break;
1542#ifdef CONFIG_SECURITY 1613#ifdef CONFIG_SECURITY
1543 case PROC_TID_ATTR: 1614 case PROC_TID_ATTR:
1544 inode->i_nlink = 2; 1615 inode->i_nlink = 2;