Blame view

fs/proc/inode.c 17.3 KB
b24413180   Greg Kroah-Hartman   License cleanup: ...
1
  // SPDX-License-Identifier: GPL-2.0
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2
3
4
5
6
  /*
   *  linux/fs/proc/inode.c
   *
   *  Copyright (C) 1991, 1992  Linus Torvalds
   */
efb1a57d9   Alexey Dobriyan   fs/proc: use __ro...
7
  #include <linux/cache.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
8
9
10
  #include <linux/time.h>
  #include <linux/proc_fs.h>
  #include <linux/kernel.h>
97412950b   Vasiliy Kulikov   procfs: parse mou...
11
  #include <linux/pid_namespace.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
12
13
14
  #include <linux/mm.h>
  #include <linux/string.h>
  #include <linux/stat.h>
786d7e161   Alexey Dobriyan   Fix rmmod/read/wr...
15
  #include <linux/completion.h>
dd23aae4f   Alexey Dobriyan   Fix select on /pr...
16
  #include <linux/poll.h>
87ebdc00e   Andrew Morton   fs/proc: clean up...
17
  #include <linux/printk.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
18
19
20
21
  #include <linux/file.h>
  #include <linux/limits.h>
  #include <linux/init.h>
  #include <linux/module.h>
9043476f7   Al Viro   [PATCH] sanitize ...
22
  #include <linux/sysctl.h>
97412950b   Vasiliy Kulikov   procfs: parse mou...
23
  #include <linux/seq_file.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
24
  #include <linux/slab.h>
97412950b   Vasiliy Kulikov   procfs: parse mou...
25
  #include <linux/mount.h>
1c6c4d112   Alexey Gladkov   proc: use human-r...
26
  #include <linux/bug.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
27

7c0f6ba68   Linus Torvalds   Replace <asm/uacc...
28
  #include <linux/uaccess.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
29

fee781e6c   Adrian Bunk   [PATCH] fs/proc/:...
30
  #include "internal.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
31

8267952b3   Al Viro   switch procfs to ...
32
  static void proc_evict_inode(struct inode *inode)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
33
34
  {
  	struct proc_dir_entry *de;
dfef6dcd3   Al Viro   unfuck proc_sysct...
35
  	struct ctl_table_header *head;
71448011e   Eric W. Biederman   proc: Clear the p...
36
  	struct proc_inode *ei = PROC_I(inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
37

91b0abe36   Johannes Weiner   mm + fs: store sh...
38
  	truncate_inode_pages_final(&inode->i_data);
dbd5768f8   Jan Kara   vfs: Rename end_w...
39
  	clear_inode(inode);
fef266580   Mark Fasheh   [PATCH] update fi...
40

99f895518   Eric W. Biederman   [PATCH] proc: don...
41
  	/* Stop tracking associated processes */
71448011e   Eric W. Biederman   proc: Clear the p...
42
  	if (ei->pid) {
7bc3e6e55   Eric W. Biederman   proc: Use a list ...
43
  		proc_pid_evict_inode(ei);
71448011e   Eric W. Biederman   proc: Clear the p...
44
45
  		ei->pid = NULL;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
46
47
  
  	/* Let go of any associated proc directory entry */
71448011e   Eric W. Biederman   proc: Clear the p...
48
49
  	de = ei->pde;
  	if (de) {
135d5655d   Alexey Dobriyan   proc: rename de_g...
50
  		pde_put(de);
71448011e   Eric W. Biederman   proc: Clear the p...
51
52
  		ei->pde = NULL;
  	}
d6cffbbe9   Konstantin Khlebnikov   proc/sysctl: prun...
53

71448011e   Eric W. Biederman   proc: Clear the p...
54
  	head = ei->sysctl;
dfef6dcd3   Al Viro   unfuck proc_sysct...
55
  	if (head) {
71448011e   Eric W. Biederman   proc: Clear the p...
56
  		RCU_INIT_POINTER(ei->sysctl, NULL);
d6cffbbe9   Konstantin Khlebnikov   proc/sysctl: prun...
57
  		proc_sys_evict_inode(inode, head);
dfef6dcd3   Al Viro   unfuck proc_sysct...
58
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
59
  }
efb1a57d9   Alexey Dobriyan   fs/proc: use __ro...
60
  static struct kmem_cache *proc_inode_cachep __ro_after_init;
195b8cf06   Alexey Dobriyan   proc: move "struc...
61
  static struct kmem_cache *pde_opener_cache __ro_after_init;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
62
63
64
65
  
  static struct inode *proc_alloc_inode(struct super_block *sb)
  {
  	struct proc_inode *ei;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
66

f245e1c17   Tobin C. Harding   fs/proc/inode.c: ...
67
  	ei = kmem_cache_alloc(proc_inode_cachep, GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
68
69
  	if (!ei)
  		return NULL;
13b41b094   Eric W. Biederman   [PATCH] proc: Use...
70
  	ei->pid = NULL;
aed7a6c47   Eric W. Biederman   [PATCH] proc: Rep...
71
  	ei->fd = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
72
73
  	ei->op.proc_get_link = NULL;
  	ei->pde = NULL;
9043476f7   Al Viro   [PATCH] sanitize ...
74
75
  	ei->sysctl = NULL;
  	ei->sysctl_entry = NULL;
0afa5ca82   Eric W. Biederman   proc: Rename in p...
76
  	INIT_HLIST_NODE(&ei->sibling_inodes);
3d3d35b1e   Al Viro   kill proc_ns comp...
77
  	ei->ns_ops = NULL;
230f72e9f   Alexey Dobriyan   fs/proc/inode.c: ...
78
  	return &ei->vfs_inode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
79
  }
4aa6b55c0   Al Viro   procfs: switch to...
80
  static void proc_free_inode(struct inode *inode)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
81
82
83
  {
  	kmem_cache_free(proc_inode_cachep, PROC_I(inode));
  }
51cc50685   Alexey Dobriyan   SL*B: drop kmem c...
84
  static void init_once(void *foo)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
85
86
  {
  	struct proc_inode *ei = (struct proc_inode *) foo;
a35afb830   Christoph Lameter   Remove SLAB_CTOR_...
87
  	inode_init_once(&ei->vfs_inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
88
  }
20c2df83d   Paul Mundt   mm: Remove slab d...
89

195b8cf06   Alexey Dobriyan   proc: move "struc...
90
  void __init proc_init_kmemcache(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
91
92
93
  {
  	proc_inode_cachep = kmem_cache_create("proc_inode_cache",
  					     sizeof(struct proc_inode),
fffb60f93   Paul Jackson   [PATCH] cpuset me...
94
  					     0, (SLAB_RECLAIM_ACCOUNT|
5d097056c   Vladimir Davydov   kmemcg: account c...
95
96
  						SLAB_MEM_SPREAD|SLAB_ACCOUNT|
  						SLAB_PANIC),
20c2df83d   Paul Mundt   mm: Remove slab d...
97
  					     init_once);
195b8cf06   Alexey Dobriyan   proc: move "struc...
98
99
  	pde_opener_cache =
  		kmem_cache_create("pde_opener", sizeof(struct pde_opener), 0,
2acddbe81   Alexey Dobriyan   proc: account "st...
100
  				  SLAB_ACCOUNT|SLAB_PANIC, NULL);
b4884f233   Alexey Dobriyan   proc: move "struc...
101
  	proc_dir_entry_cache = kmem_cache_create_usercopy(
2d6e4e822   Alexey Dobriyan   proc: fixup PDE a...
102
103
104
105
  		"proc_dir_entry", SIZEOF_PDE, 0, SLAB_PANIC,
  		offsetof(struct proc_dir_entry, inline_name),
  		SIZEOF_PDE_INLINE_NAME, NULL);
  	BUILD_BUG_ON(sizeof(struct proc_dir_entry) >= SIZEOF_PDE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
106
  }
f90f3cafe   Eric W. Biederman   proc: Use d_inval...
107
  void proc_invalidate_siblings_dcache(struct hlist_head *inodes, spinlock_t *lock)
26dbc60f3   Eric W. Biederman   proc: Generalize ...
108
109
110
111
  {
  	struct inode *inode;
  	struct proc_inode *ei;
  	struct hlist_node *node;
080f6276f   Eric W. Biederman   proc: In proc_pru...
112
  	struct super_block *old_sb = NULL;
26dbc60f3   Eric W. Biederman   proc: Generalize ...
113
114
115
  
  	rcu_read_lock();
  	for (;;) {
080f6276f   Eric W. Biederman   proc: In proc_pru...
116
  		struct super_block *sb;
26dbc60f3   Eric W. Biederman   proc: Generalize ...
117
118
119
120
121
122
123
124
125
126
  		node = hlist_first_rcu(inodes);
  		if (!node)
  			break;
  		ei = hlist_entry(node, struct proc_inode, sibling_inodes);
  		spin_lock(lock);
  		hlist_del_init_rcu(&ei->sibling_inodes);
  		spin_unlock(lock);
  
  		inode = &ei->vfs_inode;
  		sb = inode->i_sb;
080f6276f   Eric W. Biederman   proc: In proc_pru...
127
  		if ((sb != old_sb) && !atomic_inc_not_zero(&sb->s_active))
26dbc60f3   Eric W. Biederman   proc: Generalize ...
128
129
130
  			continue;
  		inode = igrab(inode);
  		rcu_read_unlock();
080f6276f   Eric W. Biederman   proc: In proc_pru...
131
132
133
134
135
  		if (sb != old_sb) {
  			if (old_sb)
  				deactivate_super(old_sb);
  			old_sb = sb;
  		}
26dbc60f3   Eric W. Biederman   proc: Generalize ...
136
  		if (unlikely(!inode)) {
26dbc60f3   Eric W. Biederman   proc: Generalize ...
137
138
139
  			rcu_read_lock();
  			continue;
  		}
f90f3cafe   Eric W. Biederman   proc: Use d_inval...
140
141
142
143
144
145
146
147
148
149
150
151
152
  		if (S_ISDIR(inode->i_mode)) {
  			struct dentry *dir = d_find_any_alias(inode);
  			if (dir) {
  				d_invalidate(dir);
  				dput(dir);
  			}
  		} else {
  			struct dentry *dentry;
  			while ((dentry = d_find_alias(inode))) {
  				d_invalidate(dentry);
  				dput(dentry);
  			}
  		}
26dbc60f3   Eric W. Biederman   proc: Generalize ...
153
  		iput(inode);
26dbc60f3   Eric W. Biederman   proc: Generalize ...
154
155
156
157
  
  		rcu_read_lock();
  	}
  	rcu_read_unlock();
080f6276f   Eric W. Biederman   proc: In proc_pru...
158
159
  	if (old_sb)
  		deactivate_super(old_sb);
26dbc60f3   Eric W. Biederman   proc: Generalize ...
160
  }
e61bb8b36   Alexey Gladkov   proc: use named e...
161
  static inline const char *hidepid2str(enum proc_hidepid v)
1c6c4d112   Alexey Gladkov   proc: use human-r...
162
163
164
165
166
167
168
169
170
171
172
  {
  	switch (v) {
  		case HIDEPID_OFF: return "off";
  		case HIDEPID_NO_ACCESS: return "noaccess";
  		case HIDEPID_INVISIBLE: return "invisible";
  		case HIDEPID_NOT_PTRACEABLE: return "ptraceable";
  	}
  	WARN_ONCE(1, "bad hide_pid value: %d
  ", v);
  	return "unknown";
  }
97412950b   Vasiliy Kulikov   procfs: parse mou...
173
174
  static int proc_show_options(struct seq_file *seq, struct dentry *root)
  {
fa10fed30   Alexey Gladkov   proc: allow to mo...
175
  	struct proc_fs_info *fs_info = proc_sb_info(root->d_sb);
0499680a4   Vasiliy Kulikov   procfs: add hidep...
176

fa10fed30   Alexey Gladkov   proc: allow to mo...
177
178
179
  	if (!gid_eq(fs_info->pid_gid, GLOBAL_ROOT_GID))
  		seq_printf(seq, ",gid=%u", from_kgid_munged(&init_user_ns, fs_info->pid_gid));
  	if (fs_info->hide_pid != HIDEPID_OFF)
1c6c4d112   Alexey Gladkov   proc: use human-r...
180
  		seq_printf(seq, ",hidepid=%s", hidepid2str(fs_info->hide_pid));
6814ef2d9   Alexey Gladkov   proc: add option ...
181
182
  	if (fs_info->pidonly != PROC_PIDONLY_OFF)
  		seq_printf(seq, ",subset=pid");
0499680a4   Vasiliy Kulikov   procfs: add hidep...
183

97412950b   Vasiliy Kulikov   procfs: parse mou...
184
185
  	return 0;
  }
60a3c3a58   David Howells   procfs: Move proc...
186
  const struct super_operations proc_sops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
187
  	.alloc_inode	= proc_alloc_inode,
4aa6b55c0   Al Viro   procfs: switch to...
188
  	.free_inode	= proc_free_inode,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
189
  	.drop_inode	= generic_delete_inode,
8267952b3   Al Viro   switch procfs to ...
190
  	.evict_inode	= proc_evict_inode,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
191
  	.statfs		= simple_statfs,
97412950b   Vasiliy Kulikov   procfs: parse mou...
192
  	.show_options	= proc_show_options,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
193
  };
866ad9a74   Al Viro   procfs: preparati...
194
195
196
197
  enum {BIAS = -1U<<31};
  
  static inline int use_pde(struct proc_dir_entry *pde)
  {
15b158b4e   Alexey Dobriyan   proc: spread like...
198
  	return likely(atomic_inc_unless_negative(&pde->in_use));
881adb853   Alexey Dobriyan   proc: always do -...
199
  }
866ad9a74   Al Viro   procfs: preparati...
200
  static void unuse_pde(struct proc_dir_entry *pde)
881adb853   Alexey Dobriyan   proc: always do -...
201
  {
15b158b4e   Alexey Dobriyan   proc: spread like...
202
  	if (unlikely(atomic_dec_return(&pde->in_use) == BIAS))
05c0ae21c   Al Viro   try a saner locki...
203
  		complete(pde->pde_unload_completion);
786d7e161   Alexey Dobriyan   Fix rmmod/read/wr...
204
  }
2f8974243   Alexey Dobriyan   proc: do less stu...
205
  /* pde is locked on entry, unlocked on exit */
ca469f35a   Al Viro   deal with races b...
206
  static void close_pdeo(struct proc_dir_entry *pde, struct pde_opener *pdeo)
904f394e2   Jules Irenge   fs/proc/inode.c: ...
207
  	__releases(&pde->pde_unload_lock)
ca469f35a   Al Viro   deal with races b...
208
  {
492b2da60   Alexey Dobriyan   proc: tweak comme...
209
210
211
212
213
214
215
216
217
218
  	/*
  	 * close() (proc_reg_release()) can't delete an entry and proceed:
  	 * ->release hook needs to be available at the right moment.
  	 *
  	 * rmmod (remove_proc_entry() et al) can't delete an entry and proceed:
  	 * "struct file" needs to be available at the right moment.
  	 *
  	 * Therefore, first process to enter this function does ->release() and
  	 * signals its completion to the other process which does nothing.
  	 */
05c0ae21c   Al Viro   try a saner locki...
219
  	if (pdeo->closing) {
ca469f35a   Al Viro   deal with races b...
220
  		/* somebody else is doing that, just wait */
05c0ae21c   Al Viro   try a saner locki...
221
222
  		DECLARE_COMPLETION_ONSTACK(c);
  		pdeo->c = &c;
ca469f35a   Al Viro   deal with races b...
223
  		spin_unlock(&pde->pde_unload_lock);
05c0ae21c   Al Viro   try a saner locki...
224
  		wait_for_completion(&c);
ca469f35a   Al Viro   deal with races b...
225
226
  	} else {
  		struct file *file;
2f8974243   Alexey Dobriyan   proc: do less stu...
227
  		struct completion *c;
f5887c71c   Alexey Dobriyan   proc: fix type of...
228
  		pdeo->closing = true;
ca469f35a   Al Viro   deal with races b...
229
230
  		spin_unlock(&pde->pde_unload_lock);
  		file = pdeo->file;
d56c0d45f   Alexey Dobriyan   proc: decouple pr...
231
  		pde->proc_ops->proc_release(file_inode(file), file);
ca469f35a   Al Viro   deal with races b...
232
  		spin_lock(&pde->pde_unload_lock);
492b2da60   Alexey Dobriyan   proc: tweak comme...
233
  		/* After ->release. */
06a0c4175   Alexey Dobriyan   proc: just list_d...
234
  		list_del(&pdeo->lh);
2f8974243   Alexey Dobriyan   proc: do less stu...
235
236
237
238
  		c = pdeo->c;
  		spin_unlock(&pde->pde_unload_lock);
  		if (unlikely(c))
  			complete(c);
195b8cf06   Alexey Dobriyan   proc: move "struc...
239
  		kmem_cache_free(pde_opener_cache, pdeo);
05c0ae21c   Al Viro   try a saner locki...
240
  	}
ca469f35a   Al Viro   deal with races b...
241
  }
866ad9a74   Al Viro   procfs: preparati...
242
  void proc_entry_rundown(struct proc_dir_entry *de)
786d7e161   Alexey Dobriyan   Fix rmmod/read/wr...
243
  {
05c0ae21c   Al Viro   try a saner locki...
244
  	DECLARE_COMPLETION_ONSTACK(c);
866ad9a74   Al Viro   procfs: preparati...
245
  	/* Wait until all existing callers into module are done. */
05c0ae21c   Al Viro   try a saner locki...
246
247
248
  	de->pde_unload_completion = &c;
  	if (atomic_add_return(BIAS, &de->in_use) != BIAS)
  		wait_for_completion(&c);
786d7e161   Alexey Dobriyan   Fix rmmod/read/wr...
249

492b2da60   Alexey Dobriyan   proc: tweak comme...
250
  	/* ->pde_openers list can't grow from now on. */
05c0ae21c   Al Viro   try a saner locki...
251
  	spin_lock(&de->pde_unload_lock);
866ad9a74   Al Viro   procfs: preparati...
252
253
  	while (!list_empty(&de->pde_openers)) {
  		struct pde_opener *pdeo;
866ad9a74   Al Viro   procfs: preparati...
254
  		pdeo = list_first_entry(&de->pde_openers, struct pde_opener, lh);
ca469f35a   Al Viro   deal with races b...
255
  		close_pdeo(de, pdeo);
2f8974243   Alexey Dobriyan   proc: do less stu...
256
  		spin_lock(&de->pde_unload_lock);
866ad9a74   Al Viro   procfs: preparati...
257
258
  	}
  	spin_unlock(&de->pde_unload_lock);
786d7e161   Alexey Dobriyan   Fix rmmod/read/wr...
259
  }
d919b33da   Alexey Dobriyan   proc: faster open...
260
261
262
263
264
265
266
267
268
  static loff_t pde_lseek(struct proc_dir_entry *pde, struct file *file, loff_t offset, int whence)
  {
  	typeof_member(struct proc_ops, proc_lseek) lseek;
  
  	lseek = pde->proc_ops->proc_lseek;
  	if (!lseek)
  		lseek = default_llseek;
  	return lseek(file, offset, whence);
  }
866ad9a74   Al Viro   procfs: preparati...
269
270
271
272
  static loff_t proc_reg_llseek(struct file *file, loff_t offset, int whence)
  {
  	struct proc_dir_entry *pde = PDE(file_inode(file));
  	loff_t rv = -EINVAL;
9af27b28b   Alexey Dobriyan   fs/proc/inode.c: ...
273

d919b33da   Alexey Dobriyan   proc: faster open...
274
275
276
277
  	if (pde_is_permanent(pde)) {
  		return pde_lseek(pde, file, offset, whence);
  	} else if (use_pde(pde)) {
  		rv = pde_lseek(pde, file, offset, whence);
866ad9a74   Al Viro   procfs: preparati...
278
279
  		unuse_pde(pde);
  	}
786d7e161   Alexey Dobriyan   Fix rmmod/read/wr...
280
281
  	return rv;
  }
fd5a13f48   Christoph Hellwig   proc: add a read_...
282
283
284
285
286
287
288
289
290
291
292
293
294
295
  static ssize_t proc_reg_read_iter(struct kiocb *iocb, struct iov_iter *iter)
  {
  	struct proc_dir_entry *pde = PDE(file_inode(iocb->ki_filp));
  	ssize_t ret;
  
  	if (pde_is_permanent(pde))
  		return pde->proc_ops->proc_read_iter(iocb, iter);
  
  	if (!use_pde(pde))
  		return -EIO;
  	ret = pde->proc_ops->proc_read_iter(iocb, iter);
  	unuse_pde(pde);
  	return ret;
  }
d919b33da   Alexey Dobriyan   proc: faster open...
296
297
298
299
300
301
302
303
304
  static ssize_t pde_read(struct proc_dir_entry *pde, struct file *file, char __user *buf, size_t count, loff_t *ppos)
  {
  	typeof_member(struct proc_ops, proc_read) read;
  
  	read = pde->proc_ops->proc_read;
  	if (read)
  		return read(file, buf, count, ppos);
  	return -EIO;
  }
866ad9a74   Al Viro   procfs: preparati...
305
  static ssize_t proc_reg_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
786d7e161   Alexey Dobriyan   Fix rmmod/read/wr...
306
  {
496ad9aa8   Al Viro   new helper: file_...
307
  	struct proc_dir_entry *pde = PDE(file_inode(file));
786d7e161   Alexey Dobriyan   Fix rmmod/read/wr...
308
  	ssize_t rv = -EIO;
9af27b28b   Alexey Dobriyan   fs/proc/inode.c: ...
309

d919b33da   Alexey Dobriyan   proc: faster open...
310
311
312
313
  	if (pde_is_permanent(pde)) {
  		return pde_read(pde, file, buf, count, ppos);
  	} else if (use_pde(pde)) {
  		rv = pde_read(pde, file, buf, count, ppos);
866ad9a74   Al Viro   procfs: preparati...
314
  		unuse_pde(pde);
786d7e161   Alexey Dobriyan   Fix rmmod/read/wr...
315
  	}
866ad9a74   Al Viro   procfs: preparati...
316
317
  	return rv;
  }
786d7e161   Alexey Dobriyan   Fix rmmod/read/wr...
318

d919b33da   Alexey Dobriyan   proc: faster open...
319
320
321
322
323
324
325
326
327
  static ssize_t pde_write(struct proc_dir_entry *pde, struct file *file, const char __user *buf, size_t count, loff_t *ppos)
  {
  	typeof_member(struct proc_ops, proc_write) write;
  
  	write = pde->proc_ops->proc_write;
  	if (write)
  		return write(file, buf, count, ppos);
  	return -EIO;
  }
866ad9a74   Al Viro   procfs: preparati...
328
329
  static ssize_t proc_reg_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
  {
866ad9a74   Al Viro   procfs: preparati...
330
331
  	struct proc_dir_entry *pde = PDE(file_inode(file));
  	ssize_t rv = -EIO;
9af27b28b   Alexey Dobriyan   fs/proc/inode.c: ...
332

d919b33da   Alexey Dobriyan   proc: faster open...
333
334
335
336
  	if (pde_is_permanent(pde)) {
  		return pde_write(pde, file, buf, count, ppos);
  	} else if (use_pde(pde)) {
  		rv = pde_write(pde, file, buf, count, ppos);
866ad9a74   Al Viro   procfs: preparati...
337
338
  		unuse_pde(pde);
  	}
786d7e161   Alexey Dobriyan   Fix rmmod/read/wr...
339
340
  	return rv;
  }
d919b33da   Alexey Dobriyan   proc: faster open...
341
342
343
344
345
346
347
348
349
  static __poll_t pde_poll(struct proc_dir_entry *pde, struct file *file, struct poll_table_struct *pts)
  {
  	typeof_member(struct proc_ops, proc_poll) poll;
  
  	poll = pde->proc_ops->proc_poll;
  	if (poll)
  		return poll(file, pts);
  	return DEFAULT_POLLMASK;
  }
076ccb76e   Al Viro   fs: annotate ->po...
350
  static __poll_t proc_reg_poll(struct file *file, struct poll_table_struct *pts)
786d7e161   Alexey Dobriyan   Fix rmmod/read/wr...
351
  {
496ad9aa8   Al Viro   new helper: file_...
352
  	struct proc_dir_entry *pde = PDE(file_inode(file));
e6c8adca2   Al Viro   anntotate the pla...
353
  	__poll_t rv = DEFAULT_POLLMASK;
9af27b28b   Alexey Dobriyan   fs/proc/inode.c: ...
354

d919b33da   Alexey Dobriyan   proc: faster open...
355
356
357
358
  	if (pde_is_permanent(pde)) {
  		return pde_poll(pde, file, pts);
  	} else if (use_pde(pde)) {
  		rv = pde_poll(pde, file, pts);
866ad9a74   Al Viro   procfs: preparati...
359
  		unuse_pde(pde);
786d7e161   Alexey Dobriyan   Fix rmmod/read/wr...
360
  	}
786d7e161   Alexey Dobriyan   Fix rmmod/read/wr...
361
362
  	return rv;
  }
d919b33da   Alexey Dobriyan   proc: faster open...
363
364
365
366
367
368
369
370
371
  static long pde_ioctl(struct proc_dir_entry *pde, struct file *file, unsigned int cmd, unsigned long arg)
  {
  	typeof_member(struct proc_ops, proc_ioctl) ioctl;
  
  	ioctl = pde->proc_ops->proc_ioctl;
  	if (ioctl)
  		return ioctl(file, cmd, arg);
  	return -ENOTTY;
  }
786d7e161   Alexey Dobriyan   Fix rmmod/read/wr...
372
373
  static long proc_reg_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
  {
496ad9aa8   Al Viro   new helper: file_...
374
  	struct proc_dir_entry *pde = PDE(file_inode(file));
786d7e161   Alexey Dobriyan   Fix rmmod/read/wr...
375
  	long rv = -ENOTTY;
9af27b28b   Alexey Dobriyan   fs/proc/inode.c: ...
376

d919b33da   Alexey Dobriyan   proc: faster open...
377
378
379
380
  	if (pde_is_permanent(pde)) {
  		return pde_ioctl(pde, file, cmd, arg);
  	} else if (use_pde(pde)) {
  		rv = pde_ioctl(pde, file, cmd, arg);
866ad9a74   Al Viro   procfs: preparati...
381
  		unuse_pde(pde);
786d7e161   Alexey Dobriyan   Fix rmmod/read/wr...
382
  	}
786d7e161   Alexey Dobriyan   Fix rmmod/read/wr...
383
384
385
386
  	return rv;
  }
  
  #ifdef CONFIG_COMPAT
d919b33da   Alexey Dobriyan   proc: faster open...
387
388
389
390
391
392
393
394
395
  static long pde_compat_ioctl(struct proc_dir_entry *pde, struct file *file, unsigned int cmd, unsigned long arg)
  {
  	typeof_member(struct proc_ops, proc_compat_ioctl) compat_ioctl;
  
  	compat_ioctl = pde->proc_ops->proc_compat_ioctl;
  	if (compat_ioctl)
  		return compat_ioctl(file, cmd, arg);
  	return -ENOTTY;
  }
786d7e161   Alexey Dobriyan   Fix rmmod/read/wr...
396
397
  static long proc_reg_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
  {
496ad9aa8   Al Viro   new helper: file_...
398
  	struct proc_dir_entry *pde = PDE(file_inode(file));
786d7e161   Alexey Dobriyan   Fix rmmod/read/wr...
399
  	long rv = -ENOTTY;
d919b33da   Alexey Dobriyan   proc: faster open...
400
401
402
403
  	if (pde_is_permanent(pde)) {
  		return pde_compat_ioctl(pde, file, cmd, arg);
  	} else if (use_pde(pde)) {
  		rv = pde_compat_ioctl(pde, file, cmd, arg);
866ad9a74   Al Viro   procfs: preparati...
404
  		unuse_pde(pde);
786d7e161   Alexey Dobriyan   Fix rmmod/read/wr...
405
  	}
786d7e161   Alexey Dobriyan   Fix rmmod/read/wr...
406
407
408
  	return rv;
  }
  #endif
d919b33da   Alexey Dobriyan   proc: faster open...
409
410
411
412
413
414
415
416
417
  static int pde_mmap(struct proc_dir_entry *pde, struct file *file, struct vm_area_struct *vma)
  {
  	typeof_member(struct proc_ops, proc_mmap) mmap;
  
  	mmap = pde->proc_ops->proc_mmap;
  	if (mmap)
  		return mmap(file, vma);
  	return -EIO;
  }
786d7e161   Alexey Dobriyan   Fix rmmod/read/wr...
418
419
  static int proc_reg_mmap(struct file *file, struct vm_area_struct *vma)
  {
496ad9aa8   Al Viro   new helper: file_...
420
  	struct proc_dir_entry *pde = PDE(file_inode(file));
786d7e161   Alexey Dobriyan   Fix rmmod/read/wr...
421
  	int rv = -EIO;
9af27b28b   Alexey Dobriyan   fs/proc/inode.c: ...
422

d919b33da   Alexey Dobriyan   proc: faster open...
423
424
425
426
  	if (pde_is_permanent(pde)) {
  		return pde_mmap(pde, file, vma);
  	} else if (use_pde(pde)) {
  		rv = pde_mmap(pde, file, vma);
866ad9a74   Al Viro   procfs: preparati...
427
  		unuse_pde(pde);
786d7e161   Alexey Dobriyan   Fix rmmod/read/wr...
428
  	}
786d7e161   Alexey Dobriyan   Fix rmmod/read/wr...
429
430
  	return rv;
  }
5721cf84d   HATAYAMA Daisuke   procfs: clean up ...
431
  static unsigned long
d919b33da   Alexey Dobriyan   proc: faster open...
432
  pde_get_unmapped_area(struct proc_dir_entry *pde, struct file *file, unsigned long orig_addr,
5721cf84d   HATAYAMA Daisuke   procfs: clean up ...
433
434
  			   unsigned long len, unsigned long pgoff,
  			   unsigned long flags)
c4fe24485   Alexey Dobriyan   sparc: fix PCI de...
435
  {
d919b33da   Alexey Dobriyan   proc: faster open...
436
  	typeof_member(struct proc_ops, proc_get_unmapped_area) get_area;
ae5758a1a   Jan Beulich   procfs: also fix ...
437

d919b33da   Alexey Dobriyan   proc: faster open...
438
  	get_area = pde->proc_ops->proc_get_unmapped_area;
fad1a86e2   HATAYAMA Daisuke   procfs: call defa...
439
  #ifdef CONFIG_MMU
d919b33da   Alexey Dobriyan   proc: faster open...
440
441
  	if (!get_area)
  		get_area = current->mm->get_unmapped_area;
fad1a86e2   HATAYAMA Daisuke   procfs: call defa...
442
  #endif
d919b33da   Alexey Dobriyan   proc: faster open...
443
444
445
446
447
448
449
450
451
452
453
454
  	if (get_area)
  		return get_area(file, orig_addr, len, pgoff, flags);
  	return orig_addr;
  }
  
  static unsigned long
  proc_reg_get_unmapped_area(struct file *file, unsigned long orig_addr,
  			   unsigned long len, unsigned long pgoff,
  			   unsigned long flags)
  {
  	struct proc_dir_entry *pde = PDE(file_inode(file));
  	unsigned long rv = -EIO;
ae5758a1a   Jan Beulich   procfs: also fix ...
455

d919b33da   Alexey Dobriyan   proc: faster open...
456
457
458
459
  	if (pde_is_permanent(pde)) {
  		return pde_get_unmapped_area(pde, file, orig_addr, len, pgoff, flags);
  	} else if (use_pde(pde)) {
  		rv = pde_get_unmapped_area(pde, file, orig_addr, len, pgoff, flags);
c4fe24485   Alexey Dobriyan   sparc: fix PCI de...
460
461
462
463
  		unuse_pde(pde);
  	}
  	return rv;
  }
786d7e161   Alexey Dobriyan   Fix rmmod/read/wr...
464
465
  static int proc_reg_open(struct inode *inode, struct file *file)
  {
6814ef2d9   Alexey Gladkov   proc: add option ...
466
  	struct proc_fs_info *fs_info = proc_sb_info(inode->i_sb);
786d7e161   Alexey Dobriyan   Fix rmmod/read/wr...
467
468
  	struct proc_dir_entry *pde = PDE(inode);
  	int rv = 0;
d56c0d45f   Alexey Dobriyan   proc: decouple pr...
469
470
  	typeof_member(struct proc_ops, proc_open) open;
  	typeof_member(struct proc_ops, proc_release) release;
881adb853   Alexey Dobriyan   proc: always do -...
471
  	struct pde_opener *pdeo;
d919b33da   Alexey Dobriyan   proc: faster open...
472
473
474
475
476
477
  	if (pde_is_permanent(pde)) {
  		open = pde->proc_ops->proc_open;
  		if (open)
  			rv = open(inode, file);
  		return rv;
  	}
6814ef2d9   Alexey Gladkov   proc: add option ...
478
479
  	if (fs_info->pidonly == PROC_PIDONLY_ON)
  		return -ENOENT;
881adb853   Alexey Dobriyan   proc: always do -...
480
  	/*
492b2da60   Alexey Dobriyan   proc: tweak comme...
481
482
483
484
485
486
487
  	 * Ensure that
  	 * 1) PDE's ->release hook will be called no matter what
  	 *    either normally by close()/->release, or forcefully by
  	 *    rmmod/remove_proc_entry.
  	 *
  	 * 2) rmmod isn't blocked by opening file in /proc and sitting on
  	 *    the descriptor (including "rmmod foo </proc/foo" scenario).
881adb853   Alexey Dobriyan   proc: always do -...
488
  	 *
492b2da60   Alexey Dobriyan   proc: tweak comme...
489
  	 * Save every "struct file" with custom ->release hook.
881adb853   Alexey Dobriyan   proc: always do -...
490
  	 */
e7a6e291e   Alexey Dobriyan   proc: faster open...
491
  	if (!use_pde(pde))
d2857e79a   Daisuke Ogino   procfs: return EN...
492
  		return -ENOENT;
e7a6e291e   Alexey Dobriyan   proc: faster open...
493

d56c0d45f   Alexey Dobriyan   proc: decouple pr...
494
  	release = pde->proc_ops->proc_release;
e7a6e291e   Alexey Dobriyan   proc: faster open...
495
  	if (release) {
195b8cf06   Alexey Dobriyan   proc: move "struc...
496
  		pdeo = kmem_cache_alloc(pde_opener_cache, GFP_KERNEL);
e7a6e291e   Alexey Dobriyan   proc: faster open...
497
498
499
500
501
  		if (!pdeo) {
  			rv = -ENOMEM;
  			goto out_unuse;
  		}
  	}
786d7e161   Alexey Dobriyan   Fix rmmod/read/wr...
502

d56c0d45f   Alexey Dobriyan   proc: decouple pr...
503
  	open = pde->proc_ops->proc_open;
786d7e161   Alexey Dobriyan   Fix rmmod/read/wr...
504
505
  	if (open)
  		rv = open(inode, file);
e7a6e291e   Alexey Dobriyan   proc: faster open...
506
507
508
509
510
511
512
513
514
515
  	if (release) {
  		if (rv == 0) {
  			/* To know what to release. */
  			pdeo->file = file;
  			pdeo->closing = false;
  			pdeo->c = NULL;
  			spin_lock(&pde->pde_unload_lock);
  			list_add(&pdeo->lh, &pde->pde_openers);
  			spin_unlock(&pde->pde_unload_lock);
  		} else
195b8cf06   Alexey Dobriyan   proc: move "struc...
516
  			kmem_cache_free(pde_opener_cache, pdeo);
e7a6e291e   Alexey Dobriyan   proc: faster open...
517
  	}
05c0ae21c   Al Viro   try a saner locki...
518

e7a6e291e   Alexey Dobriyan   proc: faster open...
519
  out_unuse:
05c0ae21c   Al Viro   try a saner locki...
520
  	unuse_pde(pde);
786d7e161   Alexey Dobriyan   Fix rmmod/read/wr...
521
522
523
524
525
526
  	return rv;
  }
  
  static int proc_reg_release(struct inode *inode, struct file *file)
  {
  	struct proc_dir_entry *pde = PDE(inode);
881adb853   Alexey Dobriyan   proc: always do -...
527
  	struct pde_opener *pdeo;
d919b33da   Alexey Dobriyan   proc: faster open...
528
529
530
531
532
533
534
535
536
537
  
  	if (pde_is_permanent(pde)) {
  		typeof_member(struct proc_ops, proc_release) release;
  
  		release = pde->proc_ops->proc_release;
  		if (release) {
  			return release(inode, file);
  		}
  		return 0;
  	}
786d7e161   Alexey Dobriyan   Fix rmmod/read/wr...
538
  	spin_lock(&pde->pde_unload_lock);
ca469f35a   Al Viro   deal with races b...
539
540
541
  	list_for_each_entry(pdeo, &pde->pde_openers, lh) {
  		if (pdeo->file == file) {
  			close_pdeo(pde, pdeo);
2f8974243   Alexey Dobriyan   proc: do less stu...
542
  			return 0;
ca469f35a   Al Viro   deal with races b...
543
  		}
881adb853   Alexey Dobriyan   proc: always do -...
544
  	}
786d7e161   Alexey Dobriyan   Fix rmmod/read/wr...
545
  	spin_unlock(&pde->pde_unload_lock);
ca469f35a   Al Viro   deal with races b...
546
  	return 0;
786d7e161   Alexey Dobriyan   Fix rmmod/read/wr...
547
548
549
550
551
552
553
554
  }
  
  static const struct file_operations proc_reg_file_ops = {
  	.llseek		= proc_reg_llseek,
  	.read		= proc_reg_read,
  	.write		= proc_reg_write,
  	.poll		= proc_reg_poll,
  	.unlocked_ioctl	= proc_reg_unlocked_ioctl,
786d7e161   Alexey Dobriyan   Fix rmmod/read/wr...
555
  	.mmap		= proc_reg_mmap,
c4fe24485   Alexey Dobriyan   sparc: fix PCI de...
556
  	.get_unmapped_area = proc_reg_get_unmapped_area,
786d7e161   Alexey Dobriyan   Fix rmmod/read/wr...
557
558
559
  	.open		= proc_reg_open,
  	.release	= proc_reg_release,
  };
fd5a13f48   Christoph Hellwig   proc: add a read_...
560
561
562
563
  static const struct file_operations proc_iter_file_ops = {
  	.llseek		= proc_reg_llseek,
  	.read_iter	= proc_reg_read_iter,
  	.write		= proc_reg_write,
86aa9dba8   Christoph Hellwig   FROMLIST: proc: w...
564
  	.splice_read	= generic_file_splice_read,
fd5a13f48   Christoph Hellwig   proc: add a read_...
565
566
567
568
569
570
571
  	.poll		= proc_reg_poll,
  	.unlocked_ioctl	= proc_reg_unlocked_ioctl,
  	.mmap		= proc_reg_mmap,
  	.get_unmapped_area = proc_reg_get_unmapped_area,
  	.open		= proc_reg_open,
  	.release	= proc_reg_release,
  };
778f3dd5a   David Miller   Fix procfs compat...
572
  #ifdef CONFIG_COMPAT
906146f44   Christoph Hellwig   proc: cleanup the...
573
  static const struct file_operations proc_reg_file_ops_compat = {
778f3dd5a   David Miller   Fix procfs compat...
574
575
576
577
578
  	.llseek		= proc_reg_llseek,
  	.read		= proc_reg_read,
  	.write		= proc_reg_write,
  	.poll		= proc_reg_poll,
  	.unlocked_ioctl	= proc_reg_unlocked_ioctl,
906146f44   Christoph Hellwig   proc: cleanup the...
579
  	.compat_ioctl	= proc_reg_compat_ioctl,
778f3dd5a   David Miller   Fix procfs compat...
580
  	.mmap		= proc_reg_mmap,
c4fe24485   Alexey Dobriyan   sparc: fix PCI de...
581
  	.get_unmapped_area = proc_reg_get_unmapped_area,
778f3dd5a   David Miller   Fix procfs compat...
582
583
584
  	.open		= proc_reg_open,
  	.release	= proc_reg_release,
  };
fd5a13f48   Christoph Hellwig   proc: add a read_...
585
586
587
588
  
  static const struct file_operations proc_iter_file_ops_compat = {
  	.llseek		= proc_reg_llseek,
  	.read_iter	= proc_reg_read_iter,
86aa9dba8   Christoph Hellwig   FROMLIST: proc: w...
589
  	.splice_read	= generic_file_splice_read,
fd5a13f48   Christoph Hellwig   proc: add a read_...
590
591
592
593
594
595
596
597
598
  	.write		= proc_reg_write,
  	.poll		= proc_reg_poll,
  	.unlocked_ioctl	= proc_reg_unlocked_ioctl,
  	.compat_ioctl	= proc_reg_compat_ioctl,
  	.mmap		= proc_reg_mmap,
  	.get_unmapped_area = proc_reg_get_unmapped_area,
  	.open		= proc_reg_open,
  	.release	= proc_reg_release,
  };
778f3dd5a   David Miller   Fix procfs compat...
599
  #endif
fceef393a   Al Viro   switch ->get_link...
600
601
602
603
  static void proc_put_link(void *p)
  {
  	unuse_pde(p);
  }
6b2553918   Al Viro   replace ->follow_...
604
  static const char *proc_get_link(struct dentry *dentry,
fceef393a   Al Viro   switch ->get_link...
605
606
  				 struct inode *inode,
  				 struct delayed_call *done)
7e0e953bb   Al Viro   procfs: fix race ...
607
  {
6b2553918   Al Viro   replace ->follow_...
608
  	struct proc_dir_entry *pde = PDE(inode);
15b158b4e   Alexey Dobriyan   proc: spread like...
609
  	if (!use_pde(pde))
7e0e953bb   Al Viro   procfs: fix race ...
610
  		return ERR_PTR(-EINVAL);
fceef393a   Al Viro   switch ->get_link...
611
  	set_delayed_call(done, proc_put_link, pde);
680baacbc   Al Viro   new ->follow_link...
612
  	return pde->data;
7e0e953bb   Al Viro   procfs: fix race ...
613
  }
7e0e953bb   Al Viro   procfs: fix race ...
614
  const struct inode_operations proc_link_inode_operations = {
6b2553918   Al Viro   replace ->follow_...
615
  	.get_link	= proc_get_link,
7e0e953bb   Al Viro   procfs: fix race ...
616
  };
6d1b6e4ef   Alexey Dobriyan   proc: ->low_ino c...
617
  struct inode *proc_get_inode(struct super_block *sb, struct proc_dir_entry *de)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
618
  {
ef1548ada   Eric W. Biederman   proc: Use new_ino...
619
  	struct inode *inode = new_inode(sb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
620

f6ef7b7bb   Christoph Hellwig   proc: remove a le...
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
  	if (!inode) {
  		pde_put(de);
  		return NULL;
  	}
  
  	inode->i_ino = de->low_ino;
  	inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode);
  	PROC_I(inode)->pde = de;
  	if (is_empty_pde(de)) {
  		make_empty_dir_inode(inode);
  		return inode;
  	}
  
  	if (de->mode) {
  		inode->i_mode = de->mode;
  		inode->i_uid = de->uid;
  		inode->i_gid = de->gid;
  	}
  	if (de->size)
  		inode->i_size = de->size;
  	if (de->nlink)
  		set_nlink(inode, de->nlink);
  
  	if (S_ISREG(inode->i_mode)) {
  		inode->i_op = de->proc_iops;
fd5a13f48   Christoph Hellwig   proc: add a read_...
646
647
648
649
  		if (de->proc_ops->proc_read_iter)
  			inode->i_fop = &proc_iter_file_ops;
  		else
  			inode->i_fop = &proc_reg_file_ops;
778f3dd5a   David Miller   Fix procfs compat...
650
  #ifdef CONFIG_COMPAT
fd5a13f48   Christoph Hellwig   proc: add a read_...
651
652
653
654
655
656
  		if (de->proc_ops->proc_compat_ioctl) {
  			if (de->proc_ops->proc_read_iter)
  				inode->i_fop = &proc_iter_file_ops_compat;
  			else
  				inode->i_fop = &proc_reg_file_ops_compat;
  		}
d56c0d45f   Alexey Dobriyan   proc: decouple pr...
657
  #endif
f6ef7b7bb   Christoph Hellwig   proc: remove a le...
658
659
660
661
662
663
664
665
666
  	} else if (S_ISDIR(inode->i_mode)) {
  		inode->i_op = de->proc_iops;
  		inode->i_fop = de->proc_dir_ops;
  	} else if (S_ISLNK(inode->i_mode)) {
  		inode->i_op = de->proc_iops;
  		inode->i_fop = NULL;
  	} else {
  		BUG();
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
667
  	return inode;
d3d009cb9   Al Viro   saner proc_get_in...
668
  }