root.c 5.3 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
/*
 *  linux/fs/proc/root.c
 *
 *  Copyright (C) 1991, 1992 Linus Torvalds
 *
 *  proc root directory handling functions
 */

#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>
16
#include <linux/sched.h>
L
Linus Torvalds 已提交
17 18
#include <linux/module.h>
#include <linux/bitops.h>
19
#include <linux/mount.h>
20
#include <linux/pid_namespace.h>
V
Vasiliy Kulikov 已提交
21
#include <linux/parser.h>
L
Linus Torvalds 已提交
22

23 24
#include "internal.h"

25 26 27 28 29 30 31
static int proc_test_super(struct super_block *sb, void *data)
{
	return sb->s_fs_info == data;
}

static int proc_set_super(struct super_block *sb, void *data)
{
A
Al Viro 已提交
32 33 34 35 36 37
	int err = set_anon_super(sb, NULL);
	if (!err) {
		struct pid_namespace *ns = (struct pid_namespace *)data;
		sb->s_fs_info = get_pid_ns(ns);
	}
	return err;
38 39
}

V
Vasiliy Kulikov 已提交
40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81
enum {
	Opt_err,
};

static const match_table_t tokens = {
	{Opt_err, NULL},
};

static int proc_parse_options(char *options, struct pid_namespace *pid)
{
	char *p;
	substring_t args[MAX_OPT_ARGS];

	pr_debug("proc: options = %s\n", options);

	if (!options)
		return 1;

	while ((p = strsep(&options, ",")) != NULL) {
		int token;
		if (!*p)
			continue;

		args[0].to = args[0].from = 0;
		token = match_token(p, tokens, args);
		switch (token) {
		default:
			pr_err("proc: unrecognized mount option \"%s\" "
			       "or missing value\n", p);
			return 0;
		}
	}

	return 1;
}

int proc_remount(struct super_block *sb, int *flags, char *data)
{
	struct pid_namespace *pid = sb->s_fs_info;
	return !proc_parse_options(data, pid);
}

A
Al Viro 已提交
82 83
static struct dentry *proc_mount(struct file_system_type *fs_type,
	int flags, const char *dev_name, void *data)
L
Linus Torvalds 已提交
84
{
85 86 87 88
	int err;
	struct super_block *sb;
	struct pid_namespace *ns;
	struct proc_inode *ei;
V
Vasiliy Kulikov 已提交
89
	char *options;
90

V
Vasiliy Kulikov 已提交
91
	if (flags & MS_KERNMOUNT) {
92
		ns = (struct pid_namespace *)data;
V
Vasiliy Kulikov 已提交
93 94
		options = NULL;
	} else {
95
		ns = current->nsproxy->pid_ns;
V
Vasiliy Kulikov 已提交
96 97
		options = data;
	}
98 99 100

	sb = sget(fs_type, proc_test_super, proc_set_super, ns);
	if (IS_ERR(sb))
A
Al Viro 已提交
101
		return ERR_CAST(sb);
102 103 104

	if (!sb->s_root) {
		sb->s_flags = flags;
V
Vasiliy Kulikov 已提交
105 106 107 108
		if (!proc_parse_options(options, ns)) {
			deactivate_locked_super(sb);
			return ERR_PTR(-EINVAL);
		}
109 110
		err = proc_fill_super(sb);
		if (err) {
111
			deactivate_locked_super(sb);
A
Al Viro 已提交
112
			return ERR_PTR(err);
113 114 115 116 117
		}

		sb->s_flags |= MS_ACTIVE;
	}

118 119 120 121 122 123 124
	ei = PROC_I(sb->s_root->d_inode);
	if (!ei->pid) {
		rcu_read_lock();
		ei->pid = get_pid(find_pid_ns(1, ns));
		rcu_read_unlock();
	}

A
Al Viro 已提交
125
	return dget(sb->s_root);
126 127 128 129 130 131 132 133 134
}

static void proc_kill_sb(struct super_block *sb)
{
	struct pid_namespace *ns;

	ns = (struct pid_namespace *)sb->s_fs_info;
	kill_anon_super(sb);
	put_pid_ns(ns);
L
Linus Torvalds 已提交
135 136
}

A
Alexey Dobriyan 已提交
137
static struct file_system_type proc_fs_type = {
L
Linus Torvalds 已提交
138
	.name		= "proc",
A
Al Viro 已提交
139
	.mount		= proc_mount,
140
	.kill_sb	= proc_kill_sb,
L
Linus Torvalds 已提交
141 142 143 144
};

void __init proc_root_init(void)
{
145 146 147
	int err;

	proc_init_inodecache();
L
Linus Torvalds 已提交
148 149 150
	err = register_filesystem(&proc_fs_type);
	if (err)
		return;
151 152
	err = pid_ns_prepare_proc(&init_pid_ns);
	if (err) {
L
Linus Torvalds 已提交
153 154 155
		unregister_filesystem(&proc_fs_type);
		return;
	}
156

A
Alexey Dobriyan 已提交
157
	proc_symlink("mounts", NULL, "self/mounts");
158 159

	proc_net_init();
L
Linus Torvalds 已提交
160 161 162 163

#ifdef CONFIG_SYSVIPC
	proc_mkdir("sysvipc", NULL);
#endif
A
Alexey Dobriyan 已提交
164
	proc_mkdir("fs", NULL);
A
Alexey Dobriyan 已提交
165
	proc_mkdir("driver", NULL);
L
Linus Torvalds 已提交
166 167 168 169 170 171 172 173 174
	proc_mkdir("fs/nfsd", NULL); /* somewhere for the nfsd filesystem to be mounted */
#if defined(CONFIG_SUN_OPENPROMFS) || defined(CONFIG_SUN_OPENPROMFS_MODULE)
	/* just give it a mountpoint */
	proc_mkdir("openprom", NULL);
#endif
	proc_tty_init();
#ifdef CONFIG_PROC_DEVICETREE
	proc_device_tree_init();
#endif
A
Alexey Dobriyan 已提交
175
	proc_mkdir("bus", NULL);
176
	proc_sys_init();
L
Linus Torvalds 已提交
177 178
}

179 180
static int proc_root_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat
)
L
Linus Torvalds 已提交
181
{
182 183 184 185
	generic_fillattr(dentry->d_inode, stat);
	stat->nlink = proc_root.nlink + nr_processes();
	return 0;
}
L
Linus Torvalds 已提交
186

187 188
static struct dentry *proc_root_lookup(struct inode * dir, struct dentry * dentry, struct nameidata *nd)
{
L
Linus Torvalds 已提交
189 190 191 192 193 194 195 196 197 198 199 200 201 202 203
	if (!proc_lookup(dir, dentry, nd)) {
		return NULL;
	}
	
	return proc_pid_lookup(dir, dentry, nd);
}

static int proc_root_readdir(struct file * filp,
	void * dirent, filldir_t filldir)
{
	unsigned int nr = filp->f_pos;
	int ret;

	if (nr < FIRST_PROCESS_ENTRY) {
		int error = proc_readdir(filp, dirent, filldir);
A
Alexey Dobriyan 已提交
204
		if (error <= 0)
L
Linus Torvalds 已提交
205 206 207 208 209 210 211 212 213 214 215 216 217
			return error;
		filp->f_pos = FIRST_PROCESS_ENTRY;
	}

	ret = proc_pid_readdir(filp, dirent, filldir);
	return ret;
}

/*
 * The root /proc directory is special, as it has the
 * <pid> directories. Thus we don't use the generic
 * directory handling functions for that..
 */
218
static const struct file_operations proc_root_operations = {
L
Linus Torvalds 已提交
219 220
	.read		 = generic_read_dir,
	.readdir	 = proc_root_readdir,
221
	.llseek		= default_llseek,
L
Linus Torvalds 已提交
222 223 224 225 226
};

/*
 * proc root can do almost nothing..
 */
227
static const struct inode_operations proc_root_inode_operations = {
L
Linus Torvalds 已提交
228
	.lookup		= proc_root_lookup,
229
	.getattr	= proc_root_getattr,
L
Linus Torvalds 已提交
230 231 232 233 234 235 236 237 238 239
};

/*
 * This is the root "inode" in the /proc tree..
 */
struct proc_dir_entry proc_root = {
	.low_ino	= PROC_ROOT_INO, 
	.namelen	= 5, 
	.mode		= S_IFDIR | S_IRUGO | S_IXUGO, 
	.nlink		= 2, 
240
	.count		= ATOMIC_INIT(1),
L
Linus Torvalds 已提交
241 242 243
	.proc_iops	= &proc_root_inode_operations, 
	.proc_fops	= &proc_root_operations,
	.parent		= &proc_root,
244
	.name		= "/proc",
L
Linus Torvalds 已提交
245 246
};

247 248 249 250 251 252 253 254
int pid_ns_prepare_proc(struct pid_namespace *ns)
{
	struct vfsmount *mnt;

	mnt = kern_mount_data(&proc_fs_type, ns);
	if (IS_ERR(mnt))
		return PTR_ERR(mnt);

255
	ns->proc_mnt = mnt;
256 257 258 259 260
	return 0;
}

void pid_ns_release_proc(struct pid_namespace *ns)
{
261
	kern_unmount(ns->proc_mnt);
262
}