⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 base.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
	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 + -