diff options
Diffstat (limited to 'fs/proc/base.c')
| -rw-r--r-- | fs/proc/base.c | 200 |
1 files changed, 137 insertions, 63 deletions
diff --git a/fs/proc/base.c b/fs/proc/base.c index ace151fa4878..23db452ab428 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> |
| @@ -28,6 +62,7 @@ | |||
| 28 | #include <linux/namespace.h> | 62 | #include <linux/namespace.h> |
| 29 | #include <linux/mm.h> | 63 | #include <linux/mm.h> |
| 30 | #include <linux/smp_lock.h> | 64 | #include <linux/smp_lock.h> |
| 65 | #include <linux/rcupdate.h> | ||
| 31 | #include <linux/kallsyms.h> | 66 | #include <linux/kallsyms.h> |
| 32 | #include <linux/mount.h> | 67 | #include <linux/mount.h> |
| 33 | #include <linux/security.h> | 68 | #include <linux/security.h> |
| @@ -65,8 +100,10 @@ enum pid_directory_inos { | |||
| 65 | PROC_TGID_STAT, | 100 | PROC_TGID_STAT, |
| 66 | PROC_TGID_STATM, | 101 | PROC_TGID_STATM, |
| 67 | PROC_TGID_MAPS, | 102 | PROC_TGID_MAPS, |
| 103 | PROC_TGID_NUMA_MAPS, | ||
| 68 | PROC_TGID_MOUNTS, | 104 | PROC_TGID_MOUNTS, |
| 69 | PROC_TGID_WCHAN, | 105 | PROC_TGID_WCHAN, |
| 106 | PROC_TGID_SMAPS, | ||
| 70 | #ifdef CONFIG_SCHEDSTATS | 107 | #ifdef CONFIG_SCHEDSTATS |
| 71 | PROC_TGID_SCHEDSTAT, | 108 | PROC_TGID_SCHEDSTAT, |
| 72 | #endif | 109 | #endif |
| @@ -83,7 +120,6 @@ enum pid_directory_inos { | |||
| 83 | #ifdef CONFIG_AUDITSYSCALL | 120 | #ifdef CONFIG_AUDITSYSCALL |
| 84 | PROC_TGID_LOGINUID, | 121 | PROC_TGID_LOGINUID, |
| 85 | #endif | 122 | #endif |
| 86 | PROC_TGID_FD_DIR, | ||
| 87 | PROC_TGID_OOM_SCORE, | 123 | PROC_TGID_OOM_SCORE, |
| 88 | PROC_TGID_OOM_ADJUST, | 124 | PROC_TGID_OOM_ADJUST, |
| 89 | PROC_TID_INO, | 125 | PROC_TID_INO, |
| @@ -102,8 +138,10 @@ enum pid_directory_inos { | |||
| 102 | PROC_TID_STAT, | 138 | PROC_TID_STAT, |
| 103 | PROC_TID_STATM, | 139 | PROC_TID_STATM, |
| 104 | PROC_TID_MAPS, | 140 | PROC_TID_MAPS, |
| 141 | PROC_TID_NUMA_MAPS, | ||
| 105 | PROC_TID_MOUNTS, | 142 | PROC_TID_MOUNTS, |
| 106 | PROC_TID_WCHAN, | 143 | PROC_TID_WCHAN, |
| 144 | PROC_TID_SMAPS, | ||
| 107 | #ifdef CONFIG_SCHEDSTATS | 145 | #ifdef CONFIG_SCHEDSTATS |
| 108 | PROC_TID_SCHEDSTAT, | 146 | PROC_TID_SCHEDSTAT, |
| 109 | #endif | 147 | #endif |
| @@ -120,9 +158,11 @@ enum pid_directory_inos { | |||
| 120 | #ifdef CONFIG_AUDITSYSCALL | 158 | #ifdef CONFIG_AUDITSYSCALL |
| 121 | PROC_TID_LOGINUID, | 159 | PROC_TID_LOGINUID, |
| 122 | #endif | 160 | #endif |
| 123 | PROC_TID_FD_DIR = 0x8000, /* 0x8000-0xffff */ | ||
| 124 | PROC_TID_OOM_SCORE, | 161 | PROC_TID_OOM_SCORE, |
| 125 | PROC_TID_OOM_ADJUST, | 162 | PROC_TID_OOM_ADJUST, |
| 163 | |||
| 164 | /* Add new entries before this */ | ||
| 165 | PROC_TID_FD_DIR = 0x8000, /* 0x8000-0xffff */ | ||
| 126 | }; | 166 | }; |
| 127 | 167 | ||
| 128 | struct pid_entry { | 168 | struct pid_entry { |
| @@ -144,6 +184,9 @@ static struct pid_entry tgid_base_stuff[] = { | |||
| 144 | E(PROC_TGID_STAT, "stat", S_IFREG|S_IRUGO), | 184 | E(PROC_TGID_STAT, "stat", S_IFREG|S_IRUGO), |
| 145 | E(PROC_TGID_STATM, "statm", S_IFREG|S_IRUGO), | 185 | E(PROC_TGID_STATM, "statm", S_IFREG|S_IRUGO), |
| 146 | E(PROC_TGID_MAPS, "maps", S_IFREG|S_IRUGO), | 186 | E(PROC_TGID_MAPS, "maps", S_IFREG|S_IRUGO), |
| 187 | #ifdef CONFIG_NUMA | ||
| 188 | E(PROC_TGID_NUMA_MAPS, "numa_maps", S_IFREG|S_IRUGO), | ||
| 189 | #endif | ||
| 147 | E(PROC_TGID_MEM, "mem", S_IFREG|S_IRUSR|S_IWUSR), | 190 | E(PROC_TGID_MEM, "mem", S_IFREG|S_IRUSR|S_IWUSR), |
| 148 | #ifdef CONFIG_SECCOMP | 191 | #ifdef CONFIG_SECCOMP |
| 149 | E(PROC_TGID_SECCOMP, "seccomp", S_IFREG|S_IRUSR|S_IWUSR), | 192 | E(PROC_TGID_SECCOMP, "seccomp", S_IFREG|S_IRUSR|S_IWUSR), |
| @@ -152,6 +195,7 @@ static struct pid_entry tgid_base_stuff[] = { | |||
| 152 | E(PROC_TGID_ROOT, "root", S_IFLNK|S_IRWXUGO), | 195 | E(PROC_TGID_ROOT, "root", S_IFLNK|S_IRWXUGO), |
| 153 | E(PROC_TGID_EXE, "exe", S_IFLNK|S_IRWXUGO), | 196 | E(PROC_TGID_EXE, "exe", S_IFLNK|S_IRWXUGO), |
| 154 | E(PROC_TGID_MOUNTS, "mounts", S_IFREG|S_IRUGO), | 197 | E(PROC_TGID_MOUNTS, "mounts", S_IFREG|S_IRUGO), |
| 198 | E(PROC_TGID_SMAPS, "smaps", S_IFREG|S_IRUGO), | ||
| 155 | #ifdef CONFIG_SECURITY | 199 | #ifdef CONFIG_SECURITY |
| 156 | E(PROC_TGID_ATTR, "attr", S_IFDIR|S_IRUGO|S_IXUGO), | 200 | E(PROC_TGID_ATTR, "attr", S_IFDIR|S_IRUGO|S_IXUGO), |
| 157 | #endif | 201 | #endif |
| @@ -180,6 +224,9 @@ static struct pid_entry tid_base_stuff[] = { | |||
| 180 | E(PROC_TID_STAT, "stat", S_IFREG|S_IRUGO), | 224 | E(PROC_TID_STAT, "stat", S_IFREG|S_IRUGO), |
| 181 | E(PROC_TID_STATM, "statm", S_IFREG|S_IRUGO), | 225 | E(PROC_TID_STATM, "statm", S_IFREG|S_IRUGO), |
| 182 | E(PROC_TID_MAPS, "maps", S_IFREG|S_IRUGO), | 226 | E(PROC_TID_MAPS, "maps", S_IFREG|S_IRUGO), |
| 227 | #ifdef CONFIG_NUMA | ||
| 228 | E(PROC_TID_NUMA_MAPS, "numa_maps", S_IFREG|S_IRUGO), | ||
| 229 | #endif | ||
| 183 | E(PROC_TID_MEM, "mem", S_IFREG|S_IRUSR|S_IWUSR), | 230 | E(PROC_TID_MEM, "mem", S_IFREG|S_IRUSR|S_IWUSR), |
| 184 | #ifdef CONFIG_SECCOMP | 231 | #ifdef CONFIG_SECCOMP |
| 185 | E(PROC_TID_SECCOMP, "seccomp", S_IFREG|S_IRUSR|S_IWUSR), | 232 | E(PROC_TID_SECCOMP, "seccomp", S_IFREG|S_IRUSR|S_IWUSR), |
| @@ -188,6 +235,7 @@ static struct pid_entry tid_base_stuff[] = { | |||
| 188 | E(PROC_TID_ROOT, "root", S_IFLNK|S_IRWXUGO), | 235 | E(PROC_TID_ROOT, "root", S_IFLNK|S_IRWXUGO), |
| 189 | E(PROC_TID_EXE, "exe", S_IFLNK|S_IRWXUGO), | 236 | E(PROC_TID_EXE, "exe", S_IFLNK|S_IRWXUGO), |
| 190 | E(PROC_TID_MOUNTS, "mounts", S_IFREG|S_IRUGO), | 237 | E(PROC_TID_MOUNTS, "mounts", S_IFREG|S_IRUGO), |
| 238 | E(PROC_TID_SMAPS, "smaps", S_IFREG|S_IRUGO), | ||
| 191 | #ifdef CONFIG_SECURITY | 239 | #ifdef CONFIG_SECURITY |
| 192 | E(PROC_TID_ATTR, "attr", S_IFDIR|S_IRUGO|S_IXUGO), | 240 | E(PROC_TID_ATTR, "attr", S_IFDIR|S_IRUGO|S_IXUGO), |
| 193 | #endif | 241 | #endif |
| @@ -236,30 +284,36 @@ static int proc_fd_link(struct inode *inode, struct dentry **dentry, struct vfsm | |||
| 236 | 284 | ||
| 237 | files = get_files_struct(task); | 285 | files = get_files_struct(task); |
| 238 | if (files) { | 286 | if (files) { |
| 239 | spin_lock(&files->file_lock); | 287 | rcu_read_lock(); |
| 240 | file = fcheck_files(files, fd); | 288 | file = fcheck_files(files, fd); |
| 241 | if (file) { | 289 | if (file) { |
| 242 | *mnt = mntget(file->f_vfsmnt); | 290 | *mnt = mntget(file->f_vfsmnt); |
| 243 | *dentry = dget(file->f_dentry); | 291 | *dentry = dget(file->f_dentry); |
| 244 | spin_unlock(&files->file_lock); | 292 | rcu_read_unlock(); |
| 245 | put_files_struct(files); | 293 | put_files_struct(files); |
| 246 | return 0; | 294 | return 0; |
| 247 | } | 295 | } |
| 248 | spin_unlock(&files->file_lock); | 296 | rcu_read_unlock(); |
| 249 | put_files_struct(files); | 297 | put_files_struct(files); |
| 250 | } | 298 | } |
| 251 | return -ENOENT; | 299 | return -ENOENT; |
| 252 | } | 300 | } |
| 253 | 301 | ||
| 254 | static int proc_cwd_link(struct inode *inode, struct dentry **dentry, struct vfsmount **mnt) | 302 | static struct fs_struct *get_fs_struct(struct task_struct *task) |
| 255 | { | 303 | { |
| 256 | struct fs_struct *fs; | 304 | struct fs_struct *fs; |
| 257 | int result = -ENOENT; | 305 | task_lock(task); |
| 258 | task_lock(proc_task(inode)); | 306 | fs = task->fs; |
| 259 | fs = proc_task(inode)->fs; | ||
| 260 | if(fs) | 307 | if(fs) |
| 261 | atomic_inc(&fs->count); | 308 | atomic_inc(&fs->count); |
| 262 | task_unlock(proc_task(inode)); | 309 | task_unlock(task); |
| 310 | return fs; | ||
| 311 | } | ||
| 312 | |||
| 313 | static int proc_cwd_link(struct inode *inode, struct dentry **dentry, struct vfsmount **mnt) | ||
| 314 | { | ||
| 315 | struct fs_struct *fs = get_fs_struct(proc_task(inode)); | ||
| 316 | int result = -ENOENT; | ||
| 263 | if (fs) { | 317 | if (fs) { |
| 264 | read_lock(&fs->lock); | 318 | read_lock(&fs->lock); |
| 265 | *mnt = mntget(fs->pwdmnt); | 319 | *mnt = mntget(fs->pwdmnt); |
| @@ -273,13 +327,8 @@ static int proc_cwd_link(struct inode *inode, struct dentry **dentry, struct vfs | |||
| 273 | 327 | ||
| 274 | static int proc_root_link(struct inode *inode, struct dentry **dentry, struct vfsmount **mnt) | 328 | static int proc_root_link(struct inode *inode, struct dentry **dentry, struct vfsmount **mnt) |
| 275 | { | 329 | { |
| 276 | struct fs_struct *fs; | 330 | struct fs_struct *fs = get_fs_struct(proc_task(inode)); |
| 277 | int result = -ENOENT; | 331 | 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) { | 332 | if (fs) { |
| 284 | read_lock(&fs->lock); | 333 | read_lock(&fs->lock); |
| 285 | *mnt = mntget(fs->rootmnt); | 334 | *mnt = mntget(fs->rootmnt); |
| @@ -298,33 +347,6 @@ static int proc_root_link(struct inode *inode, struct dentry **dentry, struct vf | |||
| 298 | (task->state == TASK_STOPPED || task->state == TASK_TRACED) && \ | 347 | (task->state == TASK_STOPPED || task->state == TASK_TRACED) && \ |
| 299 | security_ptrace(current,task) == 0)) | 348 | security_ptrace(current,task) == 0)) |
| 300 | 349 | ||
| 301 | static 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; | ||
| 323 | out: | ||
| 324 | task_unlock(task); | ||
| 325 | return retval; | ||
| 326 | } | ||
| 327 | |||
| 328 | static int proc_pid_environ(struct task_struct *task, char * buffer) | 350 | static int proc_pid_environ(struct task_struct *task, char * buffer) |
| 329 | { | 351 | { |
| 330 | int res = 0; | 352 | int res = 0; |
| @@ -334,7 +356,7 @@ static int proc_pid_environ(struct task_struct *task, char * buffer) | |||
| 334 | if (len > PAGE_SIZE) | 356 | if (len > PAGE_SIZE) |
| 335 | len = PAGE_SIZE; | 357 | len = PAGE_SIZE; |
| 336 | res = access_process_vm(task, mm->env_start, buffer, len, 0); | 358 | res = access_process_vm(task, mm->env_start, buffer, len, 0); |
| 337 | if (!may_ptrace_attach(task)) | 359 | if (!ptrace_may_attach(task)) |
| 338 | res = -ESRCH; | 360 | res = -ESRCH; |
| 339 | mmput(mm); | 361 | mmput(mm); |
| 340 | } | 362 | } |
| @@ -515,6 +537,46 @@ static struct file_operations proc_maps_operations = { | |||
| 515 | .release = seq_release, | 537 | .release = seq_release, |
| 516 | }; | 538 | }; |
| 517 | 539 | ||
| 540 | #ifdef CONFIG_NUMA | ||
| 541 | extern struct seq_operations proc_pid_numa_maps_op; | ||
| 542 | static int numa_maps_open(struct inode *inode, struct file *file) | ||
| 543 | { | ||
| 544 | struct task_struct *task = proc_task(inode); | ||
| 545 | int ret = seq_open(file, &proc_pid_numa_maps_op); | ||
| 546 | if (!ret) { | ||
| 547 | struct seq_file *m = file->private_data; | ||
| 548 | m->private = task; | ||
| 549 | } | ||
| 550 | return ret; | ||
| 551 | } | ||
| 552 | |||
| 553 | static struct file_operations proc_numa_maps_operations = { | ||
| 554 | .open = numa_maps_open, | ||
| 555 | .read = seq_read, | ||
| 556 | .llseek = seq_lseek, | ||
| 557 | .release = seq_release, | ||
| 558 | }; | ||
| 559 | #endif | ||
| 560 | |||
| 561 | extern struct seq_operations proc_pid_smaps_op; | ||
| 562 | static int smaps_open(struct inode *inode, struct file *file) | ||
| 563 | { | ||
| 564 | struct task_struct *task = proc_task(inode); | ||
| 565 | int ret = seq_open(file, &proc_pid_smaps_op); | ||
| 566 | if (!ret) { | ||
| 567 | struct seq_file *m = file->private_data; | ||
| 568 | m->private = task; | ||
| 569 | } | ||
| 570 | return ret; | ||
| 571 | } | ||
| 572 | |||
| 573 | static struct file_operations proc_smaps_operations = { | ||
| 574 | .open = smaps_open, | ||
| 575 | .read = seq_read, | ||
| 576 | .llseek = seq_lseek, | ||
| 577 | .release = seq_release, | ||
| 578 | }; | ||
| 579 | |||
| 518 | extern struct seq_operations mounts_op; | 580 | extern struct seq_operations mounts_op; |
| 519 | static int mounts_open(struct inode *inode, struct file *file) | 581 | static int mounts_open(struct inode *inode, struct file *file) |
| 520 | { | 582 | { |
| @@ -597,7 +659,7 @@ static ssize_t mem_read(struct file * file, char __user * buf, | |||
| 597 | int ret = -ESRCH; | 659 | int ret = -ESRCH; |
| 598 | struct mm_struct *mm; | 660 | struct mm_struct *mm; |
| 599 | 661 | ||
| 600 | if (!MAY_PTRACE(task) || !may_ptrace_attach(task)) | 662 | if (!MAY_PTRACE(task) || !ptrace_may_attach(task)) |
| 601 | goto out; | 663 | goto out; |
| 602 | 664 | ||
| 603 | ret = -ENOMEM; | 665 | ret = -ENOMEM; |
| @@ -623,7 +685,7 @@ static ssize_t mem_read(struct file * file, char __user * buf, | |||
| 623 | 685 | ||
| 624 | this_len = (count > PAGE_SIZE) ? PAGE_SIZE : count; | 686 | this_len = (count > PAGE_SIZE) ? PAGE_SIZE : count; |
| 625 | retval = access_process_vm(task, src, page, this_len, 0); | 687 | retval = access_process_vm(task, src, page, this_len, 0); |
| 626 | if (!retval || !MAY_PTRACE(task) || !may_ptrace_attach(task)) { | 688 | if (!retval || !MAY_PTRACE(task) || !ptrace_may_attach(task)) { |
| 627 | if (!ret) | 689 | if (!ret) |
| 628 | ret = -EIO; | 690 | ret = -EIO; |
| 629 | break; | 691 | break; |
| @@ -661,7 +723,7 @@ static ssize_t mem_write(struct file * file, const char * buf, | |||
| 661 | struct task_struct *task = proc_task(file->f_dentry->d_inode); | 723 | struct task_struct *task = proc_task(file->f_dentry->d_inode); |
| 662 | unsigned long dst = *ppos; | 724 | unsigned long dst = *ppos; |
| 663 | 725 | ||
| 664 | if (!MAY_PTRACE(task) || !may_ptrace_attach(task)) | 726 | if (!MAY_PTRACE(task) || !ptrace_may_attach(task)) |
| 665 | return -ESRCH; | 727 | return -ESRCH; |
| 666 | 728 | ||
| 667 | page = (char *)__get_free_page(GFP_USER); | 729 | page = (char *)__get_free_page(GFP_USER); |
| @@ -890,7 +952,7 @@ static struct file_operations proc_seccomp_operations = { | |||
| 890 | }; | 952 | }; |
| 891 | #endif /* CONFIG_SECCOMP */ | 953 | #endif /* CONFIG_SECCOMP */ |
| 892 | 954 | ||
| 893 | static int proc_pid_follow_link(struct dentry *dentry, struct nameidata *nd) | 955 | static void *proc_pid_follow_link(struct dentry *dentry, struct nameidata *nd) |
| 894 | { | 956 | { |
| 895 | struct inode *inode = dentry->d_inode; | 957 | struct inode *inode = dentry->d_inode; |
| 896 | int error = -EACCES; | 958 | int error = -EACCES; |
| @@ -907,7 +969,7 @@ static int proc_pid_follow_link(struct dentry *dentry, struct nameidata *nd) | |||
| 907 | error = PROC_I(inode)->op.proc_get_link(inode, &nd->dentry, &nd->mnt); | 969 | error = PROC_I(inode)->op.proc_get_link(inode, &nd->dentry, &nd->mnt); |
| 908 | nd->last_type = LAST_BIND; | 970 | nd->last_type = LAST_BIND; |
| 909 | out: | 971 | out: |
| 910 | return error; | 972 | return ERR_PTR(error); |
| 911 | } | 973 | } |
| 912 | 974 | ||
| 913 | static int do_proc_readlink(struct dentry *dentry, struct vfsmount *mnt, | 975 | static int do_proc_readlink(struct dentry *dentry, struct vfsmount *mnt, |
| @@ -978,6 +1040,7 @@ static int proc_readfd(struct file * filp, void * dirent, filldir_t filldir) | |||
| 978 | int retval; | 1040 | int retval; |
| 979 | char buf[NUMBUF]; | 1041 | char buf[NUMBUF]; |
| 980 | struct files_struct * files; | 1042 | struct files_struct * files; |
| 1043 | struct fdtable *fdt; | ||
| 981 | 1044 | ||
| 982 | retval = -ENOENT; | 1045 | retval = -ENOENT; |
| 983 | if (!pid_alive(p)) | 1046 | if (!pid_alive(p)) |
| @@ -1000,15 +1063,16 @@ static int proc_readfd(struct file * filp, void * dirent, filldir_t filldir) | |||
| 1000 | files = get_files_struct(p); | 1063 | files = get_files_struct(p); |
| 1001 | if (!files) | 1064 | if (!files) |
| 1002 | goto out; | 1065 | goto out; |
| 1003 | spin_lock(&files->file_lock); | 1066 | rcu_read_lock(); |
| 1067 | fdt = files_fdtable(files); | ||
| 1004 | for (fd = filp->f_pos-2; | 1068 | for (fd = filp->f_pos-2; |
| 1005 | fd < files->max_fds; | 1069 | fd < fdt->max_fds; |
| 1006 | fd++, filp->f_pos++) { | 1070 | fd++, filp->f_pos++) { |
| 1007 | unsigned int i,j; | 1071 | unsigned int i,j; |
| 1008 | 1072 | ||
| 1009 | if (!fcheck_files(files, fd)) | 1073 | if (!fcheck_files(files, fd)) |
| 1010 | continue; | 1074 | continue; |
| 1011 | spin_unlock(&files->file_lock); | 1075 | rcu_read_unlock(); |
| 1012 | 1076 | ||
| 1013 | j = NUMBUF; | 1077 | j = NUMBUF; |
| 1014 | i = fd; | 1078 | i = fd; |
| @@ -1020,12 +1084,12 @@ static int proc_readfd(struct file * filp, void * dirent, filldir_t filldir) | |||
| 1020 | 1084 | ||
| 1021 | ino = fake_ino(tid, PROC_TID_FD_DIR + fd); | 1085 | ino = fake_ino(tid, PROC_TID_FD_DIR + fd); |
| 1022 | if (filldir(dirent, buf+j, NUMBUF-j, fd+2, ino, DT_LNK) < 0) { | 1086 | if (filldir(dirent, buf+j, NUMBUF-j, fd+2, ino, DT_LNK) < 0) { |
| 1023 | spin_lock(&files->file_lock); | 1087 | rcu_read_lock(); |
| 1024 | break; | 1088 | break; |
| 1025 | } | 1089 | } |
| 1026 | spin_lock(&files->file_lock); | 1090 | rcu_read_lock(); |
| 1027 | } | 1091 | } |
| 1028 | spin_unlock(&files->file_lock); | 1092 | rcu_read_unlock(); |
| 1029 | put_files_struct(files); | 1093 | put_files_struct(files); |
| 1030 | } | 1094 | } |
| 1031 | out: | 1095 | out: |
| @@ -1200,9 +1264,9 @@ static int tid_fd_revalidate(struct dentry *dentry, struct nameidata *nd) | |||
| 1200 | 1264 | ||
| 1201 | files = get_files_struct(task); | 1265 | files = get_files_struct(task); |
| 1202 | if (files) { | 1266 | if (files) { |
| 1203 | spin_lock(&files->file_lock); | 1267 | rcu_read_lock(); |
| 1204 | if (fcheck_files(files, fd)) { | 1268 | if (fcheck_files(files, fd)) { |
| 1205 | spin_unlock(&files->file_lock); | 1269 | rcu_read_unlock(); |
| 1206 | put_files_struct(files); | 1270 | put_files_struct(files); |
| 1207 | if (task_dumpable(task)) { | 1271 | if (task_dumpable(task)) { |
| 1208 | inode->i_uid = task->euid; | 1272 | inode->i_uid = task->euid; |
| @@ -1214,7 +1278,7 @@ static int tid_fd_revalidate(struct dentry *dentry, struct nameidata *nd) | |||
| 1214 | security_task_to_inode(task, inode); | 1278 | security_task_to_inode(task, inode); |
| 1215 | return 1; | 1279 | return 1; |
| 1216 | } | 1280 | } |
| 1217 | spin_unlock(&files->file_lock); | 1281 | rcu_read_unlock(); |
| 1218 | put_files_struct(files); | 1282 | put_files_struct(files); |
| 1219 | } | 1283 | } |
| 1220 | d_drop(dentry); | 1284 | d_drop(dentry); |
| @@ -1306,7 +1370,7 @@ static struct dentry *proc_lookupfd(struct inode * dir, struct dentry * dentry, | |||
| 1306 | if (!files) | 1370 | if (!files) |
| 1307 | goto out_unlock; | 1371 | goto out_unlock; |
| 1308 | inode->i_mode = S_IFLNK; | 1372 | inode->i_mode = S_IFLNK; |
| 1309 | spin_lock(&files->file_lock); | 1373 | rcu_read_lock(); |
| 1310 | file = fcheck_files(files, fd); | 1374 | file = fcheck_files(files, fd); |
| 1311 | if (!file) | 1375 | if (!file) |
| 1312 | goto out_unlock2; | 1376 | goto out_unlock2; |
| @@ -1314,7 +1378,7 @@ static struct dentry *proc_lookupfd(struct inode * dir, struct dentry * dentry, | |||
| 1314 | inode->i_mode |= S_IRUSR | S_IXUSR; | 1378 | inode->i_mode |= S_IRUSR | S_IXUSR; |
| 1315 | if (file->f_mode & 2) | 1379 | if (file->f_mode & 2) |
| 1316 | inode->i_mode |= S_IWUSR | S_IXUSR; | 1380 | inode->i_mode |= S_IWUSR | S_IXUSR; |
| 1317 | spin_unlock(&files->file_lock); | 1381 | rcu_read_unlock(); |
| 1318 | put_files_struct(files); | 1382 | put_files_struct(files); |
| 1319 | inode->i_op = &proc_pid_link_inode_operations; | 1383 | inode->i_op = &proc_pid_link_inode_operations; |
| 1320 | inode->i_size = 64; | 1384 | inode->i_size = 64; |
| @@ -1324,7 +1388,7 @@ static struct dentry *proc_lookupfd(struct inode * dir, struct dentry * dentry, | |||
| 1324 | return NULL; | 1388 | return NULL; |
| 1325 | 1389 | ||
| 1326 | out_unlock2: | 1390 | out_unlock2: |
| 1327 | spin_unlock(&files->file_lock); | 1391 | rcu_read_unlock(); |
| 1328 | put_files_struct(files); | 1392 | put_files_struct(files); |
| 1329 | out_unlock: | 1393 | out_unlock: |
| 1330 | iput(inode); | 1394 | iput(inode); |
| @@ -1524,6 +1588,12 @@ static struct dentry *proc_pident_lookup(struct inode *dir, | |||
| 1524 | case PROC_TGID_MAPS: | 1588 | case PROC_TGID_MAPS: |
| 1525 | inode->i_fop = &proc_maps_operations; | 1589 | inode->i_fop = &proc_maps_operations; |
| 1526 | break; | 1590 | break; |
| 1591 | #ifdef CONFIG_NUMA | ||
| 1592 | case PROC_TID_NUMA_MAPS: | ||
| 1593 | case PROC_TGID_NUMA_MAPS: | ||
| 1594 | inode->i_fop = &proc_numa_maps_operations; | ||
| 1595 | break; | ||
| 1596 | #endif | ||
| 1527 | case PROC_TID_MEM: | 1597 | case PROC_TID_MEM: |
| 1528 | case PROC_TGID_MEM: | 1598 | case PROC_TGID_MEM: |
| 1529 | inode->i_op = &proc_mem_inode_operations; | 1599 | inode->i_op = &proc_mem_inode_operations; |
| @@ -1539,6 +1609,10 @@ static struct dentry *proc_pident_lookup(struct inode *dir, | |||
| 1539 | case PROC_TGID_MOUNTS: | 1609 | case PROC_TGID_MOUNTS: |
| 1540 | inode->i_fop = &proc_mounts_operations; | 1610 | inode->i_fop = &proc_mounts_operations; |
| 1541 | break; | 1611 | break; |
| 1612 | case PROC_TID_SMAPS: | ||
| 1613 | case PROC_TGID_SMAPS: | ||
| 1614 | inode->i_fop = &proc_smaps_operations; | ||
| 1615 | break; | ||
| 1542 | #ifdef CONFIG_SECURITY | 1616 | #ifdef CONFIG_SECURITY |
| 1543 | case PROC_TID_ATTR: | 1617 | case PROC_TID_ATTR: |
| 1544 | inode->i_nlink = 2; | 1618 | inode->i_nlink = 2; |
| @@ -1692,11 +1766,11 @@ static int proc_self_readlink(struct dentry *dentry, char __user *buffer, | |||
| 1692 | return vfs_readlink(dentry,buffer,buflen,tmp); | 1766 | return vfs_readlink(dentry,buffer,buflen,tmp); |
| 1693 | } | 1767 | } |
| 1694 | 1768 | ||
| 1695 | static int proc_self_follow_link(struct dentry *dentry, struct nameidata *nd) | 1769 | static void *proc_self_follow_link(struct dentry *dentry, struct nameidata *nd) |
| 1696 | { | 1770 | { |
| 1697 | char tmp[30]; | 1771 | char tmp[30]; |
| 1698 | sprintf(tmp, "%d", current->tgid); | 1772 | sprintf(tmp, "%d", current->tgid); |
| 1699 | return vfs_follow_link(nd,tmp); | 1773 | return ERR_PTR(vfs_follow_link(nd,tmp)); |
| 1700 | } | 1774 | } |
| 1701 | 1775 | ||
| 1702 | static struct inode_operations proc_self_inode_operations = { | 1776 | static struct inode_operations proc_self_inode_operations = { |
