📄 base.c
字号:
/* * linux/fs/proc/base.c * * Copyright (C) 1991, 1992 Linus Torvalds * * proc base directory handling functions * * 1999, Al Viro. Rewritten. Now it covers the whole per-process part. * Instead of using magical inumbers to determine the kind of object * we allocate and fill in-core inodes upon lookup. They don't even * go into icache. We cache the reference to task_struct upon lookup too. * Eventually it should become a filesystem in its own. We don't use the * rest of procfs anymore. * * * Changelog: * 17-Jan-2005 * Allan Bezerra * Bruna Moreira <bruna.moreira@indt.org.br> * Edjard Mota <edjard.mota@indt.org.br> * Ilias Biris <ilias.biris@indt.org.br> * Mauricio Lin <mauricio.lin@indt.org.br> * * Embedded Linux Lab - 10LE Instituto Nokia de Tecnologia - INdT * * A new process specific entry (smaps) included in /proc. It shows the * size of rss for each memory area. The maps entry lacks information * about physical memory size (rss) for each mapped file, i.e., * rss information for executables and library files. * This additional information is useful for any tools that need to know * about physical memory consumption for a process specific library. * * Changelog: * 21-Feb-2005 * Embedded Linux Lab - 10LE Instituto Nokia de Tecnologia - INdT * Pud inclusion in the page table walking. * * ChangeLog: * 10-Mar-2005 * 10LE Instituto Nokia de Tecnologia - INdT: * A better way to walks through the page table as suggested by Hugh Dickins. * * Simo Piiroinen <simo.piiroinen@nokia.com>: * Smaps information related to shared, private, clean and dirty pages. * * Paul Mundt <paul.mundt@nokia.com>: * Overall revision about smaps. */#include <asm/uaccess.h>#include <linux/errno.h>#include <linux/time.h>#include <linux/proc_fs.h>#include <linux/stat.h>#include <linux/init.h>#include <linux/capability.h>#include <linux/file.h>#include <linux/string.h>#include <linux/seq_file.h>#include <linux/namei.h>#include <linux/mnt_namespace.h>#include <linux/mm.h>#include <linux/rcupdate.h>#include <linux/kallsyms.h>#include <linux/resource.h>#include <linux/module.h>#include <linux/mount.h>#include <linux/security.h>#include <linux/ptrace.h>#include <linux/cgroup.h>#include <linux/cpuset.h>#include <linux/audit.h>#include <linux/poll.h>#include <linux/nsproxy.h>#include <linux/oom.h>#include <linux/elf.h>#include <linux/pid_namespace.h>#include "internal.h"/* NOTE: * Implementing inode permission operations in /proc is almost * certainly an error. Permission checks need to happen during * each system call not at open time. The reason is that most of * what we wish to check for permissions in /proc varies at runtime. * * The classic example of a problem is opening file descriptors * in /proc for a task before it execs a suid executable. *//* Worst case buffer size needed for holding an integer. */#define PROC_NUMBUF 13struct pid_entry { char *name; int len; mode_t mode; const struct inode_operations *iop; const struct file_operations *fop; union proc_op op;};#define NOD(NAME, MODE, IOP, FOP, OP) { \ .name = (NAME), \ .len = sizeof(NAME) - 1, \ .mode = MODE, \ .iop = IOP, \ .fop = FOP, \ .op = OP, \}#define DIR(NAME, MODE, OTYPE) \ NOD(NAME, (S_IFDIR|(MODE)), \ &proc_##OTYPE##_inode_operations, &proc_##OTYPE##_operations, \ {} )#define LNK(NAME, OTYPE) \ NOD(NAME, (S_IFLNK|S_IRWXUGO), \ &proc_pid_link_inode_operations, NULL, \ { .proc_get_link = &proc_##OTYPE##_link } )#define REG(NAME, MODE, OTYPE) \ NOD(NAME, (S_IFREG|(MODE)), NULL, \ &proc_##OTYPE##_operations, {})#define INF(NAME, MODE, OTYPE) \ NOD(NAME, (S_IFREG|(MODE)), \ NULL, &proc_info_file_operations, \ { .proc_read = &proc_##OTYPE } )int maps_protect;EXPORT_SYMBOL(maps_protect);static struct fs_struct *get_fs_struct(struct task_struct *task){ struct fs_struct *fs; task_lock(task); fs = task->fs; if(fs) atomic_inc(&fs->count); task_unlock(task); return fs;}static int get_nr_threads(struct task_struct *tsk){ /* Must be called with the rcu_read_lock held */ unsigned long flags; int count = 0; if (lock_task_sighand(tsk, &flags)) { count = atomic_read(&tsk->signal->count); unlock_task_sighand(tsk, &flags); } return count;}static int proc_cwd_link(struct inode *inode, struct dentry **dentry, struct vfsmount **mnt){ struct task_struct *task = get_proc_task(inode); struct fs_struct *fs = NULL; int result = -ENOENT; if (task) { fs = get_fs_struct(task); put_task_struct(task); } if (fs) { read_lock(&fs->lock); *mnt = mntget(fs->pwdmnt); *dentry = dget(fs->pwd); read_unlock(&fs->lock); result = 0; put_fs_struct(fs); } return result;}static int proc_root_link(struct inode *inode, struct dentry **dentry, struct vfsmount **mnt){ struct task_struct *task = get_proc_task(inode); struct fs_struct *fs = NULL; int result = -ENOENT; if (task) { fs = get_fs_struct(task); put_task_struct(task); } if (fs) { read_lock(&fs->lock); *mnt = mntget(fs->rootmnt); *dentry = dget(fs->root); read_unlock(&fs->lock); result = 0; put_fs_struct(fs); } return result;}#define MAY_PTRACE(task) \ (task == current || \ (task->parent == current && \ (task->ptrace & PT_PTRACED) && \ (task->state == TASK_STOPPED || task->state == TASK_TRACED) && \ security_ptrace(current,task) == 0))struct mm_struct *mm_for_maps(struct task_struct *task){ struct mm_struct *mm = get_task_mm(task); if (!mm) return NULL; down_read(&mm->mmap_sem); task_lock(task); if (task->mm != mm) goto out; if (task->mm != current->mm && __ptrace_may_attach(task) < 0) goto out; task_unlock(task); return mm;out: task_unlock(task); up_read(&mm->mmap_sem); mmput(mm); return NULL;}static int proc_pid_cmdline(struct task_struct *task, char * buffer){ int res = 0; unsigned int len; struct mm_struct *mm = get_task_mm(task); if (!mm) goto out; if (!mm->arg_end) goto out_mm; /* Shh! No looking before we're done */ len = mm->arg_end - mm->arg_start; if (len > PAGE_SIZE) len = PAGE_SIZE; res = access_process_vm(task, mm->arg_start, buffer, len, 0); // If the nul at the end of args has been overwritten, then // assume application is using setproctitle(3). if (res > 0 && buffer[res-1] != '\0' && len < PAGE_SIZE) { len = strnlen(buffer, res); if (len < res) { res = len; } else { len = mm->env_end - mm->env_start; if (len > PAGE_SIZE - res) len = PAGE_SIZE - res; res += access_process_vm(task, mm->env_start, buffer+res, len, 0); res = strnlen(buffer, res); } }out_mm: mmput(mm);out: return res;}static int proc_pid_auxv(struct task_struct *task, char *buffer){ int res = 0; struct mm_struct *mm = get_task_mm(task); if (mm) { unsigned int nwords = 0; do nwords += 2; while (mm->saved_auxv[nwords - 2] != 0); /* AT_NULL */ res = nwords * sizeof(mm->saved_auxv[0]); if (res > PAGE_SIZE) res = PAGE_SIZE; memcpy(buffer, mm->saved_auxv, res); mmput(mm); } return res;}#ifdef CONFIG_KALLSYMS/* * Provides a wchan file via kallsyms in a proper one-value-per-file format. * Returns the resolved symbol. If that fails, simply return the address. */static int proc_pid_wchan(struct task_struct *task, char *buffer){ unsigned long wchan; char symname[KSYM_NAME_LEN]; wchan = get_wchan(task); if (lookup_symbol_name(wchan, symname) < 0) return sprintf(buffer, "%lu", wchan); else return sprintf(buffer, "%s", symname);}#endif /* CONFIG_KALLSYMS */#ifdef CONFIG_SCHEDSTATS/* * Provides /proc/PID/schedstat */static int proc_pid_schedstat(struct task_struct *task, char *buffer){ return sprintf(buffer, "%llu %llu %lu\n", task->sched_info.cpu_time, task->sched_info.run_delay, task->sched_info.pcount);}#endif/* The badness from the OOM killer */unsigned long badness(struct task_struct *p, unsigned long uptime);static int proc_oom_score(struct task_struct *task, char *buffer){ unsigned long points; struct timespec uptime; do_posix_clock_monotonic_gettime(&uptime); read_lock(&tasklist_lock); points = badness(task, uptime.tv_sec); read_unlock(&tasklist_lock); return sprintf(buffer, "%lu\n", points);}struct limit_names { char *name; char *unit;};static const struct limit_names lnames[RLIM_NLIMITS] = { [RLIMIT_CPU] = {"Max cpu time", "ms"}, [RLIMIT_FSIZE] = {"Max file size", "bytes"}, [RLIMIT_DATA] = {"Max data size", "bytes"}, [RLIMIT_STACK] = {"Max stack size", "bytes"}, [RLIMIT_CORE] = {"Max core file size", "bytes"}, [RLIMIT_RSS] = {"Max resident set", "bytes"}, [RLIMIT_NPROC] = {"Max processes", "processes"}, [RLIMIT_NOFILE] = {"Max open files", "files"}, [RLIMIT_MEMLOCK] = {"Max locked memory", "bytes"}, [RLIMIT_AS] = {"Max address space", "bytes"}, [RLIMIT_LOCKS] = {"Max file locks", "locks"}, [RLIMIT_SIGPENDING] = {"Max pending signals", "signals"}, [RLIMIT_MSGQUEUE] = {"Max msgqueue size", "bytes"}, [RLIMIT_NICE] = {"Max nice priority", NULL}, [RLIMIT_RTPRIO] = {"Max realtime priority", NULL},};/* Display limits for a process */static int proc_pid_limits(struct task_struct *task, char *buffer){ unsigned int i; int count = 0; unsigned long flags; char *bufptr = buffer; struct rlimit rlim[RLIM_NLIMITS]; rcu_read_lock(); if (!lock_task_sighand(task,&flags)) { rcu_read_unlock(); return 0; } memcpy(rlim, task->signal->rlim, sizeof(struct rlimit) * RLIM_NLIMITS); unlock_task_sighand(task, &flags); rcu_read_unlock(); /* * print the file header */ count += sprintf(&bufptr[count], "%-25s %-20s %-20s %-10s\n", "Limit", "Soft Limit", "Hard Limit", "Units"); for (i = 0; i < RLIM_NLIMITS; i++) { if (rlim[i].rlim_cur == RLIM_INFINITY) count += sprintf(&bufptr[count], "%-25s %-20s ", lnames[i].name, "unlimited"); else count += sprintf(&bufptr[count], "%-25s %-20lu ", lnames[i].name, rlim[i].rlim_cur); if (rlim[i].rlim_max == RLIM_INFINITY) count += sprintf(&bufptr[count], "%-20s ", "unlimited"); else count += sprintf(&bufptr[count], "%-20lu ", rlim[i].rlim_max); if (lnames[i].unit) count += sprintf(&bufptr[count], "%-10s\n", lnames[i].unit); else count += sprintf(&bufptr[count], "\n"); } return count;}/************************************************************************//* Here the fs part begins *//************************************************************************//* permission checks */static int proc_fd_access_allowed(struct inode *inode){ struct task_struct *task; int allowed = 0; /* Allow access to a task's file descriptors if it is us or we * may use ptrace attach to the process and find out that * information. */ task = get_proc_task(inode); if (task) { allowed = ptrace_may_attach(task); put_task_struct(task); } return allowed;}static int proc_setattr(struct dentry *dentry, struct iattr *attr){ int error; struct inode *inode = dentry->d_inode; if (attr->ia_valid & ATTR_MODE) return -EPERM; error = inode_change_ok(inode, attr); if (!error) error = inode_setattr(inode, attr); return error;}static const struct inode_operations proc_def_inode_operations = { .setattr = proc_setattr,};extern struct seq_operations mounts_op;struct proc_mounts { struct seq_file m; int event;};static int mounts_open(struct inode *inode, struct file *file){ struct task_struct *task = get_proc_task(inode); struct nsproxy *nsp; struct mnt_namespace *ns = NULL; struct proc_mounts *p; int ret = -EINVAL; if (task) { rcu_read_lock(); nsp = task_nsproxy(task); if (nsp) { ns = nsp->mnt_ns; if (ns) get_mnt_ns(ns); } rcu_read_unlock(); put_task_struct(task); } if (ns) { ret = -ENOMEM; p = kmalloc(sizeof(struct proc_mounts), GFP_KERNEL); if (p) { file->private_data = &p->m; ret = seq_open(file, &mounts_op); if (!ret) { p->m.private = ns; p->event = ns->event; return 0; } kfree(p); } put_mnt_ns(ns); } return ret;}static int mounts_release(struct inode *inode, struct file *file){ struct seq_file *m = file->private_data; struct mnt_namespace *ns = m->private; put_mnt_ns(ns); return seq_release(inode, file);}static unsigned mounts_poll(struct file *file, poll_table *wait){ struct proc_mounts *p = file->private_data; struct mnt_namespace *ns = p->m.private; unsigned res = 0; poll_wait(file, &ns->poll, wait); spin_lock(&vfsmount_lock); if (p->event != ns->event) { p->event = ns->event; res = POLLERR; } spin_unlock(&vfsmount_lock); return res;}static const struct file_operations proc_mounts_operations = { .open = mounts_open, .read = seq_read, .llseek = seq_lseek, .release = mounts_release, .poll = mounts_poll,};extern struct seq_operations mountstats_op;static int mountstats_open(struct inode *inode, struct file *file){ int ret = seq_open(file, &mountstats_op); if (!ret) { struct seq_file *m = file->private_data; struct nsproxy *nsp; struct mnt_namespace *mnt_ns = NULL; struct task_struct *task = get_proc_task(inode); if (task) { rcu_read_lock(); nsp = task_nsproxy(task); if (nsp) { mnt_ns = nsp->mnt_ns; if (mnt_ns) get_mnt_ns(mnt_ns); } rcu_read_unlock(); put_task_struct(task); } if (mnt_ns) m->private = mnt_ns; else { seq_release(inode, file); ret = -EINVAL; } } return ret;}static const struct file_operations proc_mountstats_operations = { .open = mountstats_open,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -