Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e656d8a6 authored by Eric W. Biederman's avatar Eric W. Biederman
Browse files

procfs: Use the proc generic infrastructure for proc/self.



I had visions at one point of splitting proc into two filesystems.  If
that had happened proc/self being the the part of proc that actually deals
with pids would have been a nice cleanup.  As it is proc/self requires
a lot of unnecessary infrastructure for a single file.

The only user visible change is that a mounted /proc for a pid namespace
that is dead now shows a broken proc symlink, instead of being completely
invisible.  I don't think anyone will notice or care.

Signed-off-by: default avatarEric W. Biederman <ebiederm@xmission.com>
parent dd34ad35
Loading
Loading
Loading
Loading
+1 −0
Original line number Original line Diff line number Diff line
@@ -21,6 +21,7 @@ proc-y += uptime.o
proc-y	+= version.o
proc-y	+= version.o
proc-y	+= softirqs.o
proc-y	+= softirqs.o
proc-y	+= namespaces.o
proc-y	+= namespaces.o
proc-y	+= self.o
proc-$(CONFIG_PROC_SYSCTL)	+= proc_sysctl.o
proc-$(CONFIG_PROC_SYSCTL)	+= proc_sysctl.o
proc-$(CONFIG_NET)		+= proc_net.o
proc-$(CONFIG_NET)		+= proc_net.o
proc-$(CONFIG_PROC_KCORE)	+= kcore.o
proc-$(CONFIG_PROC_KCORE)	+= kcore.o
+2 −152
Original line number Original line Diff line number Diff line
@@ -2237,146 +2237,6 @@ static const struct file_operations proc_coredump_filter_operations = {
};
};
#endif
#endif


/*
 * /proc/self:
 */
static int proc_self_readlink(struct dentry *dentry, char __user *buffer,
			      int buflen)
{
	struct pid_namespace *ns = dentry->d_sb->s_fs_info;
	pid_t tgid = task_tgid_nr_ns(current, ns);
	char tmp[PROC_NUMBUF];
	if (!tgid)
		return -ENOENT;
	sprintf(tmp, "%d", tgid);
	return vfs_readlink(dentry,buffer,buflen,tmp);
}

static void *proc_self_follow_link(struct dentry *dentry, struct nameidata *nd)
{
	struct pid_namespace *ns = dentry->d_sb->s_fs_info;
	pid_t tgid = task_tgid_nr_ns(current, ns);
	char *name = ERR_PTR(-ENOENT);
	if (tgid) {
		/* 11 for max length of signed int in decimal + NULL term */
		name = kmalloc(12, GFP_KERNEL);
		if (!name)
			name = ERR_PTR(-ENOMEM);
		else
			sprintf(name, "%d", tgid);
	}
	nd_set_link(nd, name);
	return NULL;
}

static void proc_self_put_link(struct dentry *dentry, struct nameidata *nd,
				void *cookie)
{
	char *s = nd_get_link(nd);
	if (!IS_ERR(s))
		kfree(s);
}

static const struct inode_operations proc_self_inode_operations = {
	.readlink	= proc_self_readlink,
	.follow_link	= proc_self_follow_link,
	.put_link	= proc_self_put_link,
};

/*
 * proc base
 *
 * These are the directory entries in the root directory of /proc
 * that properly belong to the /proc filesystem, as they describe
 * describe something that is process related.
 */
static const struct pid_entry proc_base_stuff[] = {
	NOD("self", S_IFLNK|S_IRWXUGO,
		&proc_self_inode_operations, NULL, {}),
};

static struct dentry *proc_base_instantiate(struct inode *dir,
	struct dentry *dentry, struct task_struct *task, const void *ptr)
{
	const struct pid_entry *p = ptr;
	struct inode *inode;
	struct proc_inode *ei;
	struct dentry *error;

	/* Allocate the inode */
	error = ERR_PTR(-ENOMEM);
	inode = new_inode(dir->i_sb);
	if (!inode)
		goto out;

	/* Initialize the inode */
	ei = PROC_I(inode);
	inode->i_ino = get_next_ino();
	inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;

	/*
	 * grab the reference to the task.
	 */
	ei->pid = get_task_pid(task, PIDTYPE_PID);
	if (!ei->pid)
		goto out_iput;

	inode->i_mode = p->mode;
	if (S_ISDIR(inode->i_mode))
		set_nlink(inode, 2);
	if (S_ISLNK(inode->i_mode))
		inode->i_size = 64;
	if (p->iop)
		inode->i_op = p->iop;
	if (p->fop)
		inode->i_fop = p->fop;
	ei->op = p->op;
	d_add(dentry, inode);
	error = NULL;
out:
	return error;
out_iput:
	iput(inode);
	goto out;
}

static struct dentry *proc_base_lookup(struct inode *dir, struct dentry *dentry)
{
	struct dentry *error;
	struct task_struct *task = get_proc_task(dir);
	const struct pid_entry *p, *last;

	error = ERR_PTR(-ENOENT);

	if (!task)
		goto out_no_task;

	/* Lookup the directory entry */
	last = &proc_base_stuff[ARRAY_SIZE(proc_base_stuff) - 1];
	for (p = proc_base_stuff; p <= last; p++) {
		if (p->len != dentry->d_name.len)
			continue;
		if (!memcmp(dentry->d_name.name, p->name, p->len))
			break;
	}
	if (p > last)
		goto out;

	error = proc_base_instantiate(dir, dentry, task, p);

out:
	put_task_struct(task);
out_no_task:
	return error;
}

static int proc_base_fill_cache(struct file *filp, void *dirent,
	filldir_t filldir, struct task_struct *task, const struct pid_entry *p)
{
	return proc_fill_cache(filp, dirent, filldir, p->name, p->len,
				proc_base_instantiate, task, p);
}

#ifdef CONFIG_TASK_IO_ACCOUNTING
#ifdef CONFIG_TASK_IO_ACCOUNTING
static int do_io_accounting(struct task_struct *task, char *buffer, int whole)
static int do_io_accounting(struct task_struct *task, char *buffer, int whole)
{
{
@@ -2767,15 +2627,11 @@ static struct dentry *proc_pid_instantiate(struct inode *dir,


struct dentry *proc_pid_lookup(struct inode *dir, struct dentry * dentry, unsigned int flags)
struct dentry *proc_pid_lookup(struct inode *dir, struct dentry * dentry, unsigned int flags)
{
{
	struct dentry *result;
	struct dentry *result = NULL;
	struct task_struct *task;
	struct task_struct *task;
	unsigned tgid;
	unsigned tgid;
	struct pid_namespace *ns;
	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);
	tgid = name_to_int(dentry);
	if (tgid == ~0U)
	if (tgid == ~0U)
		goto out;
		goto out;
@@ -2838,7 +2694,7 @@ static struct tgid_iter next_tgid(struct pid_namespace *ns, struct tgid_iter ite
	return iter;
	return iter;
}
}


#define TGID_OFFSET (FIRST_PROCESS_ENTRY + ARRAY_SIZE(proc_base_stuff))
#define TGID_OFFSET (FIRST_PROCESS_ENTRY)


static int proc_pid_fill_cache(struct file *filp, void *dirent, filldir_t filldir,
static int proc_pid_fill_cache(struct file *filp, void *dirent, filldir_t filldir,
	struct tgid_iter iter)
	struct tgid_iter iter)
@@ -2872,12 +2728,6 @@ int proc_pid_readdir(struct file * filp, void * dirent, filldir_t filldir)
	if (!reaper)
	if (!reaper)
		goto out_no_task;
		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;
	ns = filp->f_dentry->d_sb->s_fs_info;
	iter.task = NULL;
	iter.task = NULL;
	iter.tgid = filp->f_pos - TGID_OFFSET;
	iter.tgid = filp->f_pos - TGID_OFFSET;
+1 −0
Original line number Original line Diff line number Diff line
@@ -15,6 +15,7 @@ struct ctl_table_header;
struct  mempolicy;
struct  mempolicy;


extern struct proc_dir_entry proc_root;
extern struct proc_dir_entry proc_root;
extern void proc_self_init(void);
#ifdef CONFIG_PROC_SYSCTL
#ifdef CONFIG_PROC_SYSCTL
extern int proc_sys_init(void);
extern int proc_sys_init(void);
extern void sysctl_head_put(struct ctl_table_header *head);
extern void sysctl_head_put(struct ctl_table_header *head);
+1 −0
Original line number Original line Diff line number Diff line
@@ -169,6 +169,7 @@ void __init proc_root_init(void)
		return;
		return;
	}
	}


	proc_self_init();
	proc_symlink("mounts", NULL, "self/mounts");
	proc_symlink("mounts", NULL, "self/mounts");


	proc_net_init();
	proc_net_init();

fs/proc/self.c

0 → 100644
+59 −0
Original line number Original line Diff line number Diff line
#include <linux/proc_fs.h>
#include <linux/sched.h>
#include <linux/namei.h>

/*
 * /proc/self:
 */
static int proc_self_readlink(struct dentry *dentry, char __user *buffer,
			      int buflen)
{
	struct pid_namespace *ns = dentry->d_sb->s_fs_info;
	pid_t tgid = task_tgid_nr_ns(current, ns);
	char tmp[PROC_NUMBUF];
	if (!tgid)
		return -ENOENT;
	sprintf(tmp, "%d", tgid);
	return vfs_readlink(dentry,buffer,buflen,tmp);
}

static void *proc_self_follow_link(struct dentry *dentry, struct nameidata *nd)
{
	struct pid_namespace *ns = dentry->d_sb->s_fs_info;
	pid_t tgid = task_tgid_nr_ns(current, ns);
	char *name = ERR_PTR(-ENOENT);
	if (tgid) {
		/* 11 for max length of signed int in decimal + NULL term */
		name = kmalloc(12, GFP_KERNEL);
		if (!name)
			name = ERR_PTR(-ENOMEM);
		else
			sprintf(name, "%d", tgid);
	}
	nd_set_link(nd, name);
	return NULL;
}

static void proc_self_put_link(struct dentry *dentry, struct nameidata *nd,
				void *cookie)
{
	char *s = nd_get_link(nd);
	if (!IS_ERR(s))
		kfree(s);
}

static const struct inode_operations proc_self_inode_operations = {
	.readlink	= proc_self_readlink,
	.follow_link	= proc_self_follow_link,
	.put_link	= proc_self_put_link,
};

void __init proc_self_init(void)
{
	struct proc_dir_entry *proc_self_symlink;
	mode_t mode;

	mode = S_IFLNK | S_IRWXUGO;
	proc_self_symlink = proc_create("self", mode, NULL, NULL );
	proc_self_symlink->proc_iops = &proc_self_inode_operations;
}