diff options
author | Eric W. Biederman <ebiederm@xmission.com> | 2010-07-10 17:52:49 -0400 |
---|---|---|
committer | Eric W. Biederman <ebiederm@xmission.com> | 2012-11-19 06:09:34 -0500 |
commit | e656d8a6f7fdf7612d2f5771f0ddfca9487f59d9 (patch) | |
tree | 66479ae4b636517e0e54e78b4ec95acadd0aec7a /fs/proc | |
parent | dd34ad35c32bb3d16789d8d4084aead7e68a7b09 (diff) |
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: Eric W. Biederman <ebiederm@xmission.com>
Diffstat (limited to 'fs/proc')
-rw-r--r-- | fs/proc/Makefile | 1 | ||||
-rw-r--r-- | fs/proc/base.c | 154 | ||||
-rw-r--r-- | fs/proc/internal.h | 1 | ||||
-rw-r--r-- | fs/proc/root.c | 1 | ||||
-rw-r--r-- | fs/proc/self.c | 59 |
5 files changed, 64 insertions, 152 deletions
diff --git a/fs/proc/Makefile b/fs/proc/Makefile index 99349efbbc2b..981b05601931 100644 --- a/fs/proc/Makefile +++ b/fs/proc/Makefile | |||
@@ -21,6 +21,7 @@ proc-y += uptime.o | |||
21 | proc-y += version.o | 21 | proc-y += version.o |
22 | proc-y += softirqs.o | 22 | proc-y += softirqs.o |
23 | proc-y += namespaces.o | 23 | proc-y += namespaces.o |
24 | proc-y += self.o | ||
24 | proc-$(CONFIG_PROC_SYSCTL) += proc_sysctl.o | 25 | proc-$(CONFIG_PROC_SYSCTL) += proc_sysctl.o |
25 | proc-$(CONFIG_NET) += proc_net.o | 26 | proc-$(CONFIG_NET) += proc_net.o |
26 | proc-$(CONFIG_PROC_KCORE) += kcore.o | 27 | proc-$(CONFIG_PROC_KCORE) += kcore.o |
diff --git a/fs/proc/base.c b/fs/proc/base.c index 144a96732dd7..cbe454e94af8 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c | |||
@@ -2237,146 +2237,6 @@ static const struct file_operations proc_coredump_filter_operations = { | |||
2237 | }; | 2237 | }; |
2238 | #endif | 2238 | #endif |
2239 | 2239 | ||
2240 | /* | ||
2241 | * /proc/self: | ||
2242 | */ | ||
2243 | static int proc_self_readlink(struct dentry *dentry, char __user *buffer, | ||
2244 | int buflen) | ||
2245 | { | ||
2246 | struct pid_namespace *ns = dentry->d_sb->s_fs_info; | ||
2247 | pid_t tgid = task_tgid_nr_ns(current, ns); | ||
2248 | char tmp[PROC_NUMBUF]; | ||
2249 | if (!tgid) | ||
2250 | return -ENOENT; | ||
2251 | sprintf(tmp, "%d", tgid); | ||
2252 | return vfs_readlink(dentry,buffer,buflen,tmp); | ||
2253 | } | ||
2254 | |||
2255 | static void *proc_self_follow_link(struct dentry *dentry, struct nameidata *nd) | ||
2256 | { | ||
2257 | struct pid_namespace *ns = dentry->d_sb->s_fs_info; | ||
2258 | pid_t tgid = task_tgid_nr_ns(current, ns); | ||
2259 | char *name = ERR_PTR(-ENOENT); | ||
2260 | if (tgid) { | ||
2261 | /* 11 for max length of signed int in decimal + NULL term */ | ||
2262 | name = kmalloc(12, GFP_KERNEL); | ||
2263 | if (!name) | ||
2264 | name = ERR_PTR(-ENOMEM); | ||
2265 | else | ||
2266 | sprintf(name, "%d", tgid); | ||
2267 | } | ||
2268 | nd_set_link(nd, name); | ||
2269 | return NULL; | ||
2270 | } | ||
2271 | |||
2272 | static void proc_self_put_link(struct dentry *dentry, struct nameidata *nd, | ||
2273 | void *cookie) | ||
2274 | { | ||
2275 | char *s = nd_get_link(nd); | ||
2276 | if (!IS_ERR(s)) | ||
2277 | kfree(s); | ||
2278 | } | ||
2279 | |||
2280 | static const struct inode_operations proc_self_inode_operations = { | ||
2281 | .readlink = proc_self_readlink, | ||
2282 | .follow_link = proc_self_follow_link, | ||
2283 | .put_link = proc_self_put_link, | ||
2284 | }; | ||
2285 | |||
2286 | /* | ||
2287 | * proc base | ||
2288 | * | ||
2289 | * These are the directory entries in the root directory of /proc | ||
2290 | * that properly belong to the /proc filesystem, as they describe | ||
2291 | * describe something that is process related. | ||
2292 | */ | ||
2293 | static const struct pid_entry proc_base_stuff[] = { | ||
2294 | NOD("self", S_IFLNK|S_IRWXUGO, | ||
2295 | &proc_self_inode_operations, NULL, {}), | ||
2296 | }; | ||
2297 | |||
2298 | static struct dentry *proc_base_instantiate(struct inode *dir, | ||
2299 | struct dentry *dentry, struct task_struct *task, const void *ptr) | ||
2300 | { | ||
2301 | const struct pid_entry *p = ptr; | ||
2302 | struct inode *inode; | ||
2303 | struct proc_inode *ei; | ||
2304 | struct dentry *error; | ||
2305 | |||
2306 | /* Allocate the inode */ | ||
2307 | error = ERR_PTR(-ENOMEM); | ||
2308 | inode = new_inode(dir->i_sb); | ||
2309 | if (!inode) | ||
2310 | goto out; | ||
2311 | |||
2312 | /* Initialize the inode */ | ||
2313 | ei = PROC_I(inode); | ||
2314 | inode->i_ino = get_next_ino(); | ||
2315 | inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; | ||
2316 | |||
2317 | /* | ||
2318 | * grab the reference to the task. | ||
2319 | */ | ||
2320 | ei->pid = get_task_pid(task, PIDTYPE_PID); | ||
2321 | if (!ei->pid) | ||
2322 | goto out_iput; | ||
2323 | |||
2324 | inode->i_mode = p->mode; | ||
2325 | if (S_ISDIR(inode->i_mode)) | ||
2326 | set_nlink(inode, 2); | ||
2327 | if (S_ISLNK(inode->i_mode)) | ||
2328 | inode->i_size = 64; | ||
2329 | if (p->iop) | ||
2330 | inode->i_op = p->iop; | ||
2331 | if (p->fop) | ||
2332 | inode->i_fop = p->fop; | ||
2333 | ei->op = p->op; | ||
2334 | d_add(dentry, inode); | ||
2335 | error = NULL; | ||
2336 | out: | ||
2337 | return error; | ||
2338 | out_iput: | ||
2339 | iput(inode); | ||
2340 | goto out; | ||
2341 | } | ||
2342 | |||
2343 | static struct dentry *proc_base_lookup(struct inode *dir, struct dentry *dentry) | ||
2344 | { | ||
2345 | struct dentry *error; | ||
2346 | struct task_struct *task = get_proc_task(dir); | ||
2347 | const struct pid_entry *p, *last; | ||
2348 | |||
2349 | error = ERR_PTR(-ENOENT); | ||
2350 | |||
2351 | if (!task) | ||
2352 | goto out_no_task; | ||
2353 | |||
2354 | /* Lookup the directory entry */ | ||
2355 | last = &proc_base_stuff[ARRAY_SIZE(proc_base_stuff) - 1]; | ||
2356 | for (p = proc_base_stuff; p <= last; p++) { | ||
2357 | if (p->len != dentry->d_name.len) | ||
2358 | continue; | ||
2359 | if (!memcmp(dentry->d_name.name, p->name, p->len)) | ||
2360 | break; | ||
2361 | } | ||
2362 | if (p > last) | ||
2363 | goto out; | ||
2364 | |||
2365 | error = proc_base_instantiate(dir, dentry, task, p); | ||
2366 | |||
2367 | out: | ||
2368 | put_task_struct(task); | ||
2369 | out_no_task: | ||
2370 | return error; | ||
2371 | } | ||
2372 | |||
2373 | static int proc_base_fill_cache(struct file *filp, void *dirent, | ||
2374 | filldir_t filldir, struct task_struct *task, const struct pid_entry *p) | ||
2375 | { | ||
2376 | return proc_fill_cache(filp, dirent, filldir, p->name, p->len, | ||
2377 | proc_base_instantiate, task, p); | ||
2378 | } | ||
2379 | |||
2380 | #ifdef CONFIG_TASK_IO_ACCOUNTING | 2240 | #ifdef CONFIG_TASK_IO_ACCOUNTING |
2381 | static int do_io_accounting(struct task_struct *task, char *buffer, int whole) | 2241 | static int do_io_accounting(struct task_struct *task, char *buffer, int whole) |
2382 | { | 2242 | { |
@@ -2767,15 +2627,11 @@ out: | |||
2767 | 2627 | ||
2768 | struct dentry *proc_pid_lookup(struct inode *dir, struct dentry * dentry, unsigned int flags) | 2628 | struct dentry *proc_pid_lookup(struct inode *dir, struct dentry * dentry, unsigned int flags) |
2769 | { | 2629 | { |
2770 | struct dentry *result; | 2630 | struct dentry *result = NULL; |
2771 | struct task_struct *task; | 2631 | struct task_struct *task; |
2772 | unsigned tgid; | 2632 | unsigned tgid; |
2773 | struct pid_namespace *ns; | 2633 | struct pid_namespace *ns; |
2774 | 2634 | ||
2775 | result = proc_base_lookup(dir, dentry); | ||
2776 | if (!IS_ERR(result) || PTR_ERR(result) != -ENOENT) | ||
2777 | goto out; | ||
2778 | |||
2779 | tgid = name_to_int(dentry); | 2635 | tgid = name_to_int(dentry); |
2780 | if (tgid == ~0U) | 2636 | if (tgid == ~0U) |
2781 | goto out; | 2637 | goto out; |
@@ -2838,7 +2694,7 @@ retry: | |||
2838 | return iter; | 2694 | return iter; |
2839 | } | 2695 | } |
2840 | 2696 | ||
2841 | #define TGID_OFFSET (FIRST_PROCESS_ENTRY + ARRAY_SIZE(proc_base_stuff)) | 2697 | #define TGID_OFFSET (FIRST_PROCESS_ENTRY) |
2842 | 2698 | ||
2843 | static int proc_pid_fill_cache(struct file *filp, void *dirent, filldir_t filldir, | 2699 | static int proc_pid_fill_cache(struct file *filp, void *dirent, filldir_t filldir, |
2844 | struct tgid_iter iter) | 2700 | struct tgid_iter iter) |
@@ -2872,12 +2728,6 @@ int proc_pid_readdir(struct file * filp, void * dirent, filldir_t filldir) | |||
2872 | if (!reaper) | 2728 | if (!reaper) |
2873 | goto out_no_task; | 2729 | goto out_no_task; |
2874 | 2730 | ||
2875 | for (; nr < ARRAY_SIZE(proc_base_stuff); filp->f_pos++, nr++) { | ||
2876 | const struct pid_entry *p = &proc_base_stuff[nr]; | ||
2877 | if (proc_base_fill_cache(filp, dirent, filldir, reaper, p) < 0) | ||
2878 | goto out; | ||
2879 | } | ||
2880 | |||
2881 | ns = filp->f_dentry->d_sb->s_fs_info; | 2731 | ns = filp->f_dentry->d_sb->s_fs_info; |
2882 | iter.task = NULL; | 2732 | iter.task = NULL; |
2883 | iter.tgid = filp->f_pos - TGID_OFFSET; | 2733 | iter.tgid = filp->f_pos - TGID_OFFSET; |
diff --git a/fs/proc/internal.h b/fs/proc/internal.h index 43973b084abf..252544c05207 100644 --- a/fs/proc/internal.h +++ b/fs/proc/internal.h | |||
@@ -15,6 +15,7 @@ struct ctl_table_header; | |||
15 | struct mempolicy; | 15 | struct mempolicy; |
16 | 16 | ||
17 | extern struct proc_dir_entry proc_root; | 17 | extern struct proc_dir_entry proc_root; |
18 | extern void proc_self_init(void); | ||
18 | #ifdef CONFIG_PROC_SYSCTL | 19 | #ifdef CONFIG_PROC_SYSCTL |
19 | extern int proc_sys_init(void); | 20 | extern int proc_sys_init(void); |
20 | extern void sysctl_head_put(struct ctl_table_header *head); | 21 | extern void sysctl_head_put(struct ctl_table_header *head); |
diff --git a/fs/proc/root.c b/fs/proc/root.c index 9889a92d2e01..5da984959edc 100644 --- a/fs/proc/root.c +++ b/fs/proc/root.c | |||
@@ -169,6 +169,7 @@ void __init proc_root_init(void) | |||
169 | return; | 169 | return; |
170 | } | 170 | } |
171 | 171 | ||
172 | proc_self_init(); | ||
172 | proc_symlink("mounts", NULL, "self/mounts"); | 173 | proc_symlink("mounts", NULL, "self/mounts"); |
173 | 174 | ||
174 | proc_net_init(); | 175 | proc_net_init(); |
diff --git a/fs/proc/self.c b/fs/proc/self.c new file mode 100644 index 000000000000..aa5cc3bff140 --- /dev/null +++ b/fs/proc/self.c | |||
@@ -0,0 +1,59 @@ | |||
1 | #include <linux/proc_fs.h> | ||
2 | #include <linux/sched.h> | ||
3 | #include <linux/namei.h> | ||
4 | |||
5 | /* | ||
6 | * /proc/self: | ||
7 | */ | ||
8 | static int proc_self_readlink(struct dentry *dentry, char __user *buffer, | ||
9 | int buflen) | ||
10 | { | ||
11 | struct pid_namespace *ns = dentry->d_sb->s_fs_info; | ||
12 | pid_t tgid = task_tgid_nr_ns(current, ns); | ||
13 | char tmp[PROC_NUMBUF]; | ||
14 | if (!tgid) | ||
15 | return -ENOENT; | ||
16 | sprintf(tmp, "%d", tgid); | ||
17 | return vfs_readlink(dentry,buffer,buflen,tmp); | ||
18 | } | ||
19 | |||
20 | static void *proc_self_follow_link(struct dentry *dentry, struct nameidata *nd) | ||
21 | { | ||
22 | struct pid_namespace *ns = dentry->d_sb->s_fs_info; | ||
23 | pid_t tgid = task_tgid_nr_ns(current, ns); | ||
24 | char *name = ERR_PTR(-ENOENT); | ||
25 | if (tgid) { | ||
26 | /* 11 for max length of signed int in decimal + NULL term */ | ||
27 | name = kmalloc(12, GFP_KERNEL); | ||
28 | if (!name) | ||
29 | name = ERR_PTR(-ENOMEM); | ||
30 | else | ||
31 | sprintf(name, "%d", tgid); | ||
32 | } | ||
33 | nd_set_link(nd, name); | ||
34 | return NULL; | ||
35 | } | ||
36 | |||
37 | static void proc_self_put_link(struct dentry *dentry, struct nameidata *nd, | ||
38 | void *cookie) | ||
39 | { | ||
40 | char *s = nd_get_link(nd); | ||
41 | if (!IS_ERR(s)) | ||
42 | kfree(s); | ||
43 | } | ||
44 | |||
45 | static const struct inode_operations proc_self_inode_operations = { | ||
46 | .readlink = proc_self_readlink, | ||
47 | .follow_link = proc_self_follow_link, | ||
48 | .put_link = proc_self_put_link, | ||
49 | }; | ||
50 | |||
51 | void __init proc_self_init(void) | ||
52 | { | ||
53 | struct proc_dir_entry *proc_self_symlink; | ||
54 | mode_t mode; | ||
55 | |||
56 | mode = S_IFLNK | S_IRWXUGO; | ||
57 | proc_self_symlink = proc_create("self", mode, NULL, NULL ); | ||
58 | proc_self_symlink->proc_iops = &proc_self_inode_operations; | ||
59 | } | ||