📄 base.c
字号:
INF("statm", S_IRUGO, pid_statm), REG("maps", S_IRUGO, maps),#ifdef CONFIG_NUMA REG("numa_maps", S_IRUGO, numa_maps),#endif REG("mem", S_IRUSR|S_IWUSR, mem), LNK("cwd", cwd), LNK("root", root), LNK("exe", exe), REG("mounts", S_IRUGO, mounts), REG("mountstats", S_IRUSR, mountstats),#ifdef CONFIG_MMU REG("clear_refs", S_IWUSR, clear_refs), REG("smaps", S_IRUGO, smaps),#endif#ifdef CONFIG_SECURITY DIR("attr", S_IRUGO|S_IXUGO, attr_dir),#endif#ifdef CONFIG_KALLSYMS INF("wchan", S_IRUGO, pid_wchan),#endif#ifdef CONFIG_SCHEDSTATS INF("schedstat", S_IRUGO, pid_schedstat),#endif#ifdef CONFIG_PROC_PID_CPUSET REG("cpuset", S_IRUGO, cpuset),#endif#ifdef CONFIG_CGROUPS REG("cgroup", S_IRUGO, cgroup),#endif INF("oom_score", S_IRUGO, oom_score), REG("oom_adj", S_IRUGO|S_IWUSR, oom_adjust),#ifdef CONFIG_AUDITSYSCALL REG("loginuid", S_IWUSR|S_IRUGO, loginuid),#endif#ifdef CONFIG_FAULT_INJECTION REG("make-it-fail", S_IRUGO|S_IWUSR, fault_inject),#endif#if defined(USE_ELF_CORE_DUMP) && defined(CONFIG_ELF_CORE) REG("coredump_filter", S_IRUGO|S_IWUSR, coredump_filter),#endif#ifdef CONFIG_TASK_IO_ACCOUNTING INF("io", S_IRUGO, pid_io_accounting),#endif};static int proc_tgid_base_readdir(struct file * filp, void * dirent, filldir_t filldir){ return proc_pident_readdir(filp,dirent,filldir, tgid_base_stuff,ARRAY_SIZE(tgid_base_stuff));}static const struct file_operations proc_tgid_base_operations = { .read = generic_read_dir, .readdir = proc_tgid_base_readdir,};static struct dentry *proc_tgid_base_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd){ return proc_pident_lookup(dir, dentry, tgid_base_stuff, ARRAY_SIZE(tgid_base_stuff));}static const struct inode_operations proc_tgid_base_inode_operations = { .lookup = proc_tgid_base_lookup, .getattr = pid_getattr, .setattr = proc_setattr,};static void proc_flush_task_mnt(struct vfsmount *mnt, pid_t pid, pid_t tgid){ struct dentry *dentry, *leader, *dir; char buf[PROC_NUMBUF]; struct qstr name; name.name = buf; name.len = snprintf(buf, sizeof(buf), "%d", pid); dentry = d_hash_and_lookup(mnt->mnt_root, &name); if (dentry) { shrink_dcache_parent(dentry); d_drop(dentry); dput(dentry); } if (tgid == 0) goto out; name.name = buf; name.len = snprintf(buf, sizeof(buf), "%d", tgid); leader = d_hash_and_lookup(mnt->mnt_root, &name); if (!leader) goto out; name.name = "task"; name.len = strlen(name.name); dir = d_hash_and_lookup(leader, &name); if (!dir) goto out_put_leader; name.name = buf; name.len = snprintf(buf, sizeof(buf), "%d", pid); dentry = d_hash_and_lookup(dir, &name); if (dentry) { shrink_dcache_parent(dentry); d_drop(dentry); dput(dentry); } dput(dir);out_put_leader: dput(leader);out: return;}/** * proc_flush_task - Remove dcache entries for @task from the /proc dcache. * @task: task that should be flushed. * * When flushing dentries from proc, one needs to flush them from global * proc (proc_mnt) and from all the namespaces' procs this task was seen * in. This call is supposed to do all of this job. * * Looks in the dcache for * /proc/@pid * /proc/@tgid/task/@pid * if either directory is present flushes it and all of it'ts children * from the dcache. * * It is safe and reasonable to cache /proc entries for a task until * that task exits. After that they just clog up the dcache with * useless entries, possibly causing useful dcache entries to be * flushed instead. This routine is proved to flush those useless * dcache entries at process exit time. * * NOTE: This routine is just an optimization so it does not guarantee * that no dcache entries will exist at process exit time it * just makes it very unlikely that any will persist. */void proc_flush_task(struct task_struct *task){ int i; struct pid *pid, *tgid = NULL; struct upid *upid; pid = task_pid(task); if (thread_group_leader(task)) tgid = task_tgid(task); for (i = 0; i <= pid->level; i++) { upid = &pid->numbers[i]; proc_flush_task_mnt(upid->ns->proc_mnt, upid->nr, tgid ? tgid->numbers[i].nr : 0); } upid = &pid->numbers[pid->level]; if (upid->nr == 1) pid_ns_release_proc(upid->ns);}static struct dentry *proc_pid_instantiate(struct inode *dir, struct dentry * dentry, struct task_struct *task, const void *ptr){ struct dentry *error = ERR_PTR(-ENOENT); struct inode *inode; inode = proc_pid_make_inode(dir->i_sb, task); if (!inode) goto out; inode->i_mode = S_IFDIR|S_IRUGO|S_IXUGO; inode->i_op = &proc_tgid_base_inode_operations; inode->i_fop = &proc_tgid_base_operations; inode->i_flags|=S_IMMUTABLE; inode->i_nlink = 5;#ifdef CONFIG_SECURITY inode->i_nlink += 1;#endif dentry->d_op = &pid_dentry_operations; d_add(dentry, inode); /* Close the race of the process dying before we return the dentry */ if (pid_revalidate(dentry, NULL)) error = NULL;out: return error;}struct dentry *proc_pid_lookup(struct inode *dir, struct dentry * dentry, struct nameidata *nd){ struct dentry *result = ERR_PTR(-ENOENT); struct task_struct *task; unsigned tgid; struct pid_namespace *ns; result = proc_base_lookup(dir, dentry); if (!IS_ERR(result) || PTR_ERR(result) != -ENOENT) goto out; tgid = name_to_int(dentry); if (tgid == ~0U) goto out; ns = dentry->d_sb->s_fs_info; rcu_read_lock(); task = find_task_by_pid_ns(tgid, ns); if (task) get_task_struct(task); rcu_read_unlock(); if (!task) goto out; result = proc_pid_instantiate(dir, dentry, task, NULL); put_task_struct(task);out: return result;}/* * Find the first task with tgid >= tgid * */struct tgid_iter { unsigned int tgid; struct task_struct *task;};static struct tgid_iter next_tgid(struct pid_namespace *ns, struct tgid_iter iter){ struct pid *pid; if (iter.task) put_task_struct(iter.task); rcu_read_lock();retry: iter.task = NULL; pid = find_ge_pid(iter.tgid, ns); if (pid) { iter.tgid = pid_nr_ns(pid, ns); iter.task = pid_task(pid, PIDTYPE_PID); /* What we to know is if the pid we have find is the * pid of a thread_group_leader. Testing for task * being a thread_group_leader is the obvious thing * todo but there is a window when it fails, due to * the pid transfer logic in de_thread. * * So we perform the straight forward test of seeing * if the pid we have found is the pid of a thread * group leader, and don't worry if the task we have * found doesn't happen to be a thread group leader. * As we don't care in the case of readdir. */ if (!iter.task || !has_group_leader_pid(iter.task)) { iter.tgid += 1; goto retry; } get_task_struct(iter.task); } rcu_read_unlock(); return iter;}#define TGID_OFFSET (FIRST_PROCESS_ENTRY + ARRAY_SIZE(proc_base_stuff))static int proc_pid_fill_cache(struct file *filp, void *dirent, filldir_t filldir, struct tgid_iter iter){ char name[PROC_NUMBUF]; int len = snprintf(name, sizeof(name), "%d", iter.tgid); return proc_fill_cache(filp, dirent, filldir, name, len, proc_pid_instantiate, iter.task, NULL);}/* for the /proc/ directory itself, after non-process stuff has been done */int proc_pid_readdir(struct file * filp, void * dirent, filldir_t filldir){ unsigned int nr = filp->f_pos - FIRST_PROCESS_ENTRY; struct task_struct *reaper = get_proc_task(filp->f_path.dentry->d_inode); struct tgid_iter iter; struct pid_namespace *ns; if (!reaper) goto out_no_task; for (; nr < ARRAY_SIZE(proc_base_stuff); filp->f_pos++, nr++) { const struct pid_entry *p = &proc_base_stuff[nr]; if (proc_base_fill_cache(filp, dirent, filldir, reaper, p) < 0) goto out; } ns = filp->f_dentry->d_sb->s_fs_info; iter.task = NULL; iter.tgid = filp->f_pos - TGID_OFFSET; for (iter = next_tgid(ns, iter); iter.task; iter.tgid += 1, iter = next_tgid(ns, iter)) { filp->f_pos = iter.tgid + TGID_OFFSET; if (proc_pid_fill_cache(filp, dirent, filldir, iter) < 0) { put_task_struct(iter.task); goto out; } } filp->f_pos = PID_MAX_LIMIT + TGID_OFFSET;out: put_task_struct(reaper);out_no_task: return 0;}/* * Tasks */static const struct pid_entry tid_base_stuff[] = { DIR("fd", S_IRUSR|S_IXUSR, fd), DIR("fdinfo", S_IRUSR|S_IXUSR, fdinfo), REG("environ", S_IRUSR, environ), INF("auxv", S_IRUSR, pid_auxv), INF("status", S_IRUGO, pid_status), INF("limits", S_IRUSR, pid_limits),#ifdef CONFIG_SCHED_DEBUG REG("sched", S_IRUGO|S_IWUSR, pid_sched),#endif INF("cmdline", S_IRUGO, pid_cmdline), INF("stat", S_IRUGO, tid_stat), INF("statm", S_IRUGO, pid_statm), REG("maps", S_IRUGO, maps),#ifdef CONFIG_NUMA REG("numa_maps", S_IRUGO, numa_maps),#endif REG("mem", S_IRUSR|S_IWUSR, mem), LNK("cwd", cwd), LNK("root", root), LNK("exe", exe), REG("mounts", S_IRUGO, mounts),#ifdef CONFIG_MMU REG("clear_refs", S_IWUSR, clear_refs), REG("smaps", S_IRUGO, smaps),#endif#ifdef CONFIG_SECURITY DIR("attr", S_IRUGO|S_IXUGO, attr_dir),#endif#ifdef CONFIG_KALLSYMS INF("wchan", S_IRUGO, pid_wchan),#endif#ifdef CONFIG_SCHEDSTATS INF("schedstat", S_IRUGO, pid_schedstat),#endif#ifdef CONFIG_PROC_PID_CPUSET REG("cpuset", S_IRUGO, cpuset),#endif#ifdef CONFIG_CGROUPS REG("cgroup", S_IRUGO, cgroup),#endif INF("oom_score", S_IRUGO, oom_score), REG("oom_adj", S_IRUGO|S_IWUSR, oom_adjust),#ifdef CONFIG_AUDITSYSCALL REG("loginuid", S_IWUSR|S_IRUGO, loginuid),#endif#ifdef CONFIG_FAULT_INJECTION REG("make-it-fail", S_IRUGO|S_IWUSR, fault_inject),#endif};static int proc_tid_base_readdir(struct file * filp, void * dirent, filldir_t filldir){ return proc_pident_readdir(filp,dirent,filldir, tid_base_stuff,ARRAY_SIZE(tid_base_stuff));}static struct dentry *proc_tid_base_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd){ return proc_pident_lookup(dir, dentry, tid_base_stuff, ARRAY_SIZE(tid_base_stuff));}static const struct file_operations proc_tid_base_operations = { .read = generic_read_dir, .readdir = proc_tid_base_readdir,};static const struct inode_operations proc_tid_base_inode_operations = { .lookup = proc_tid_base_lookup, .getattr = pid_getattr, .setattr = proc_setattr,};static struct dentry *proc_task_instantiate(struct inode *dir, struct dentry *dentry, struct task_struct *task, const void *ptr){ struct dentry *error = ERR_PTR(-ENOENT); struct inode *inode; inode = proc_pid_make_inode(dir->i_sb, task); if (!inode) goto out; inode->i_mode = S_IFDIR|S_IRUGO|S_IXUGO; inode->i_op = &proc_tid_base_inode_operations; inode->i_fop = &proc_tid_base_operations; inode->i_flags|=S_IMMUTABLE; inode->i_nlink = 4;#ifdef CONFIG_SECURITY inode->i_nlink += 1;#endif dentry->d_op = &pid_dentry_operations; d_add(dentry, inode); /* Close the race of the process dying before we return the dentry */ if (pid_revalidate(dentry, NULL)) error = NULL;out: return error;}static struct dentry *proc_task_lookup(struct inode *dir, struct dentry * dentry, struct nameidata *nd){ struct dentry *result = ERR_PTR(-ENOENT); struct task_struct *task; struct task_struct *leader = get_proc_task(dir); unsigned tid; struct pid_namespace *ns; if (!leader) goto out_no_task; tid = name_to_int(dentry); if (tid == ~0U) goto out; ns = dentry->d_sb->s_fs_info; rcu_read_lock(); task = find_task_by_pid_ns(tid, ns); if (task) get_task_struct(task); rcu_read_unlock(); if (!task) goto out; if (!same_thread_group(leader, task)) goto out_drop_task; result = proc_task_instantiate(dir, dentry, task, NULL);out_drop_task: put_task_struct(task);out: put_task_struct(leader);out_no_task: return result;}/* * Find the first tid of a thread group to return to user space. * * Usually this is just the thread group leader, but if the users * buffer was too small or there was a seek into the middle of the * directory we have more work todo. * * In the case of a short read we start with find_task_by_pid. * * In the case of a seek we start with the leader and walk nr * threads past it. */static struct task_struct *first_tid(struct task_struct *leader, int tid, int nr, struct pid_namespace *ns){ struct task_struct *pos; rcu_read_lock(); /* Attempt to start with the pid of a thread */ if (tid && (nr > 0)) { pos = find_task_by_pid_ns(tid, ns); if (pos && (pos->group_leader == leader)) goto found; } /* If nr exceeds the number of threads there is nothing todo */ pos = NULL; if (nr && nr >= get_nr_threads(leader)) goto out; /* If we haven't found our starting place yet start * with the leader and walk nr threads forward. */ for (pos = leader; nr > 0; --nr) { pos = next_thread(pos); if (pos == leader) { pos = NULL; goto out; } }found: get_task_struct(pos);out: rcu_read_unlock(); return pos;}/* * Find the next thread in the thread list. * Return NULL if there is an error or no next thread. * * The reference to the input task_struct is released. */static struct task_struct *next_tid(struct task_struct *start){ struct task_struct *pos = NULL; rcu_read_lock(); if (pid_alive(start)) { pos = next_thread(start); if (thread_group_leader(pos)) pos = NULL; else get_task_struct(pos); } rcu_read_unlock(); put_task_struct(start); return pos;}static int proc_task_fill_cache(struct file *filp, void *dirent, filldir_t filldir, struct task_struct *task, int tid){ char name[PROC_NUMBUF]; int len = snprintf(name, sizeof(name), "%d", tid); return proc_fill_cache(filp, dirent, filldir, name, len, proc_task_instantiate, task, NULL);}/* for the /proc/TGID/task/ directories */static int proc_task_readdir(struct file * filp, void * dirent, filldir_t filldir){ struct dentry *dentry = filp->f_path.dentry; struct inode *inode = dentry->d_inode; struct task_struct *leader = NULL; struct task_struct *task; int retval = -ENOENT; ino_t ino; int tid; unsigned long pos = filp->f_pos; /* avoiding "long long" filp->f_pos */ struct pid_namespace *ns; task = get_proc_task(inode); if (!task) goto out_no_task; rcu_read_lock(); if (pid_alive(task)) { leader
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -