Blame view

fs/proc/inode.c 11.9 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>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
26

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

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

8267952b3   Al Viro   switch procfs to ...
31
  static void proc_evict_inode(struct inode *inode)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
32
33
  {
  	struct proc_dir_entry *de;
dfef6dcd3   Al Viro   unfuck proc_sysct...
34
  	struct ctl_table_header *head;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
35

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

99f895518   Eric W. Biederman   [PATCH] proc: don...
39
  	/* Stop tracking associated processes */
13b41b094   Eric W. Biederman   [PATCH] proc: Use...
40
  	put_pid(PROC_I(inode)->pid);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
41
42
  
  	/* Let go of any associated proc directory entry */
6bee55f94   Alexander Kuleshov   fs: proc: use PDE...
43
  	de = PDE(inode);
99b762338   Alexey Dobriyan   proc 2/2: remove ...
44
  	if (de)
135d5655d   Alexey Dobriyan   proc: rename de_g...
45
  		pde_put(de);
d6cffbbe9   Konstantin Khlebnikov   proc/sysctl: prun...
46

dfef6dcd3   Al Viro   unfuck proc_sysct...
47
48
  	head = PROC_I(inode)->sysctl;
  	if (head) {
1c44dbc82   Monam Agarwal   fs/proc/inode.c: ...
49
  		RCU_INIT_POINTER(PROC_I(inode)->sysctl, NULL);
d6cffbbe9   Konstantin Khlebnikov   proc/sysctl: prun...
50
  		proc_sys_evict_inode(inode, head);
dfef6dcd3   Al Viro   unfuck proc_sysct...
51
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
52
  }
efb1a57d9   Alexey Dobriyan   fs/proc: use __ro...
53
  static struct kmem_cache *proc_inode_cachep __ro_after_init;
195b8cf06   Alexey Dobriyan   proc: move "struc...
54
  static struct kmem_cache *pde_opener_cache __ro_after_init;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
55
56
57
58
  
  static struct inode *proc_alloc_inode(struct super_block *sb)
  {
  	struct proc_inode *ei;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
59

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

195b8cf06   Alexey Dobriyan   proc: move "struc...
82
  void __init proc_init_kmemcache(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
83
84
85
  {
  	proc_inode_cachep = kmem_cache_create("proc_inode_cache",
  					     sizeof(struct proc_inode),
fffb60f93   Paul Jackson   [PATCH] cpuset me...
86
  					     0, (SLAB_RECLAIM_ACCOUNT|
5d097056c   Vladimir Davydov   kmemcg: account c...
87
88
  						SLAB_MEM_SPREAD|SLAB_ACCOUNT|
  						SLAB_PANIC),
20c2df83d   Paul Mundt   mm: Remove slab d...
89
  					     init_once);
195b8cf06   Alexey Dobriyan   proc: move "struc...
90
91
  	pde_opener_cache =
  		kmem_cache_create("pde_opener", sizeof(struct pde_opener), 0,
2acddbe81   Alexey Dobriyan   proc: account "st...
92
  				  SLAB_ACCOUNT|SLAB_PANIC, NULL);
b4884f233   Alexey Dobriyan   proc: move "struc...
93
  	proc_dir_entry_cache = kmem_cache_create_usercopy(
2d6e4e822   Alexey Dobriyan   proc: fixup PDE a...
94
95
96
97
  		"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
98
  }
97412950b   Vasiliy Kulikov   procfs: parse mou...
99
100
  static int proc_show_options(struct seq_file *seq, struct dentry *root)
  {
0499680a4   Vasiliy Kulikov   procfs: add hidep...
101
102
  	struct super_block *sb = root->d_sb;
  	struct pid_namespace *pid = sb->s_fs_info;
dcb0f2228   Eric W. Biederman   userns: Convert p...
103
104
  	if (!gid_eq(pid->pid_gid, GLOBAL_ROOT_GID))
  		seq_printf(seq, ",gid=%u", from_kgid_munged(&init_user_ns, pid->pid_gid));
796f571b0   Lafcadio Wluiki   procfs: use an en...
105
  	if (pid->hide_pid != HIDEPID_OFF)
0499680a4   Vasiliy Kulikov   procfs: add hidep...
106
  		seq_printf(seq, ",hidepid=%u", pid->hide_pid);
97412950b   Vasiliy Kulikov   procfs: parse mou...
107
108
  	return 0;
  }
60a3c3a58   David Howells   procfs: Move proc...
109
  const struct super_operations proc_sops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
110
  	.alloc_inode	= proc_alloc_inode,
4aa6b55c0   Al Viro   procfs: switch to...
111
  	.free_inode	= proc_free_inode,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
112
  	.drop_inode	= generic_delete_inode,
8267952b3   Al Viro   switch procfs to ...
113
  	.evict_inode	= proc_evict_inode,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
114
  	.statfs		= simple_statfs,
97412950b   Vasiliy Kulikov   procfs: parse mou...
115
  	.show_options	= proc_show_options,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
116
  };
866ad9a74   Al Viro   procfs: preparati...
117
118
119
120
  enum {BIAS = -1U<<31};
  
  static inline int use_pde(struct proc_dir_entry *pde)
  {
15b158b4e   Alexey Dobriyan   proc: spread like...
121
  	return likely(atomic_inc_unless_negative(&pde->in_use));
881adb853   Alexey Dobriyan   proc: always do -...
122
  }
866ad9a74   Al Viro   procfs: preparati...
123
  static void unuse_pde(struct proc_dir_entry *pde)
881adb853   Alexey Dobriyan   proc: always do -...
124
  {
15b158b4e   Alexey Dobriyan   proc: spread like...
125
  	if (unlikely(atomic_dec_return(&pde->in_use) == BIAS))
05c0ae21c   Al Viro   try a saner locki...
126
  		complete(pde->pde_unload_completion);
786d7e161   Alexey Dobriyan   Fix rmmod/read/wr...
127
  }
2f8974243   Alexey Dobriyan   proc: do less stu...
128
  /* pde is locked on entry, unlocked on exit */
ca469f35a   Al Viro   deal with races b...
129
130
  static void close_pdeo(struct proc_dir_entry *pde, struct pde_opener *pdeo)
  {
492b2da60   Alexey Dobriyan   proc: tweak comme...
131
132
133
134
135
136
137
138
139
140
  	/*
  	 * 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...
141
  	if (pdeo->closing) {
ca469f35a   Al Viro   deal with races b...
142
  		/* somebody else is doing that, just wait */
05c0ae21c   Al Viro   try a saner locki...
143
144
  		DECLARE_COMPLETION_ONSTACK(c);
  		pdeo->c = &c;
ca469f35a   Al Viro   deal with races b...
145
  		spin_unlock(&pde->pde_unload_lock);
05c0ae21c   Al Viro   try a saner locki...
146
  		wait_for_completion(&c);
ca469f35a   Al Viro   deal with races b...
147
148
  	} else {
  		struct file *file;
2f8974243   Alexey Dobriyan   proc: do less stu...
149
  		struct completion *c;
f5887c71c   Alexey Dobriyan   proc: fix type of...
150
  		pdeo->closing = true;
ca469f35a   Al Viro   deal with races b...
151
152
  		spin_unlock(&pde->pde_unload_lock);
  		file = pdeo->file;
d56c0d45f   Alexey Dobriyan   proc: decouple pr...
153
  		pde->proc_ops->proc_release(file_inode(file), file);
ca469f35a   Al Viro   deal with races b...
154
  		spin_lock(&pde->pde_unload_lock);
492b2da60   Alexey Dobriyan   proc: tweak comme...
155
  		/* After ->release. */
06a0c4175   Alexey Dobriyan   proc: just list_d...
156
  		list_del(&pdeo->lh);
2f8974243   Alexey Dobriyan   proc: do less stu...
157
158
159
160
  		c = pdeo->c;
  		spin_unlock(&pde->pde_unload_lock);
  		if (unlikely(c))
  			complete(c);
195b8cf06   Alexey Dobriyan   proc: move "struc...
161
  		kmem_cache_free(pde_opener_cache, pdeo);
05c0ae21c   Al Viro   try a saner locki...
162
  	}
ca469f35a   Al Viro   deal with races b...
163
  }
866ad9a74   Al Viro   procfs: preparati...
164
  void proc_entry_rundown(struct proc_dir_entry *de)
786d7e161   Alexey Dobriyan   Fix rmmod/read/wr...
165
  {
05c0ae21c   Al Viro   try a saner locki...
166
  	DECLARE_COMPLETION_ONSTACK(c);
866ad9a74   Al Viro   procfs: preparati...
167
  	/* Wait until all existing callers into module are done. */
05c0ae21c   Al Viro   try a saner locki...
168
169
170
  	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...
171

492b2da60   Alexey Dobriyan   proc: tweak comme...
172
  	/* ->pde_openers list can't grow from now on. */
05c0ae21c   Al Viro   try a saner locki...
173
  	spin_lock(&de->pde_unload_lock);
866ad9a74   Al Viro   procfs: preparati...
174
175
  	while (!list_empty(&de->pde_openers)) {
  		struct pde_opener *pdeo;
866ad9a74   Al Viro   procfs: preparati...
176
  		pdeo = list_first_entry(&de->pde_openers, struct pde_opener, lh);
ca469f35a   Al Viro   deal with races b...
177
  		close_pdeo(de, pdeo);
2f8974243   Alexey Dobriyan   proc: do less stu...
178
  		spin_lock(&de->pde_unload_lock);
866ad9a74   Al Viro   procfs: preparati...
179
180
  	}
  	spin_unlock(&de->pde_unload_lock);
786d7e161   Alexey Dobriyan   Fix rmmod/read/wr...
181
  }
866ad9a74   Al Viro   procfs: preparati...
182
183
184
185
186
  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;
  	if (use_pde(pde)) {
d56c0d45f   Alexey Dobriyan   proc: decouple pr...
187
  		typeof_member(struct proc_ops, proc_lseek) lseek;
9af27b28b   Alexey Dobriyan   fs/proc/inode.c: ...
188

d56c0d45f   Alexey Dobriyan   proc: decouple pr...
189
190
191
192
  		lseek = pde->proc_ops->proc_lseek;
  		if (!lseek)
  			lseek = default_llseek;
  		rv = lseek(file, offset, whence);
866ad9a74   Al Viro   procfs: preparati...
193
194
  		unuse_pde(pde);
  	}
786d7e161   Alexey Dobriyan   Fix rmmod/read/wr...
195
196
  	return rv;
  }
866ad9a74   Al Viro   procfs: preparati...
197
  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...
198
  {
496ad9aa8   Al Viro   new helper: file_...
199
  	struct proc_dir_entry *pde = PDE(file_inode(file));
786d7e161   Alexey Dobriyan   Fix rmmod/read/wr...
200
  	ssize_t rv = -EIO;
866ad9a74   Al Viro   procfs: preparati...
201
  	if (use_pde(pde)) {
d56c0d45f   Alexey Dobriyan   proc: decouple pr...
202
  		typeof_member(struct proc_ops, proc_read) read;
9af27b28b   Alexey Dobriyan   fs/proc/inode.c: ...
203

d56c0d45f   Alexey Dobriyan   proc: decouple pr...
204
  		read = pde->proc_ops->proc_read;
866ad9a74   Al Viro   procfs: preparati...
205
206
207
  		if (read)
  			rv = read(file, buf, count, ppos);
  		unuse_pde(pde);
786d7e161   Alexey Dobriyan   Fix rmmod/read/wr...
208
  	}
866ad9a74   Al Viro   procfs: preparati...
209
210
  	return rv;
  }
786d7e161   Alexey Dobriyan   Fix rmmod/read/wr...
211

866ad9a74   Al Viro   procfs: preparati...
212
213
  static ssize_t proc_reg_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
  {
866ad9a74   Al Viro   procfs: preparati...
214
215
216
  	struct proc_dir_entry *pde = PDE(file_inode(file));
  	ssize_t rv = -EIO;
  	if (use_pde(pde)) {
d56c0d45f   Alexey Dobriyan   proc: decouple pr...
217
  		typeof_member(struct proc_ops, proc_write) write;
9af27b28b   Alexey Dobriyan   fs/proc/inode.c: ...
218

d56c0d45f   Alexey Dobriyan   proc: decouple pr...
219
  		write = pde->proc_ops->proc_write;
866ad9a74   Al Viro   procfs: preparati...
220
221
222
223
  		if (write)
  			rv = write(file, buf, count, ppos);
  		unuse_pde(pde);
  	}
786d7e161   Alexey Dobriyan   Fix rmmod/read/wr...
224
225
  	return rv;
  }
076ccb76e   Al Viro   fs: annotate ->po...
226
  static __poll_t proc_reg_poll(struct file *file, struct poll_table_struct *pts)
786d7e161   Alexey Dobriyan   Fix rmmod/read/wr...
227
  {
496ad9aa8   Al Viro   new helper: file_...
228
  	struct proc_dir_entry *pde = PDE(file_inode(file));
e6c8adca2   Al Viro   anntotate the pla...
229
  	__poll_t rv = DEFAULT_POLLMASK;
866ad9a74   Al Viro   procfs: preparati...
230
  	if (use_pde(pde)) {
d56c0d45f   Alexey Dobriyan   proc: decouple pr...
231
  		typeof_member(struct proc_ops, proc_poll) poll;
9af27b28b   Alexey Dobriyan   fs/proc/inode.c: ...
232

d56c0d45f   Alexey Dobriyan   proc: decouple pr...
233
  		poll = pde->proc_ops->proc_poll;
866ad9a74   Al Viro   procfs: preparati...
234
235
236
  		if (poll)
  			rv = poll(file, pts);
  		unuse_pde(pde);
786d7e161   Alexey Dobriyan   Fix rmmod/read/wr...
237
  	}
786d7e161   Alexey Dobriyan   Fix rmmod/read/wr...
238
239
240
241
242
  	return rv;
  }
  
  static long proc_reg_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
  {
496ad9aa8   Al Viro   new helper: file_...
243
  	struct proc_dir_entry *pde = PDE(file_inode(file));
786d7e161   Alexey Dobriyan   Fix rmmod/read/wr...
244
  	long rv = -ENOTTY;
866ad9a74   Al Viro   procfs: preparati...
245
  	if (use_pde(pde)) {
d56c0d45f   Alexey Dobriyan   proc: decouple pr...
246
  		typeof_member(struct proc_ops, proc_ioctl) ioctl;
9af27b28b   Alexey Dobriyan   fs/proc/inode.c: ...
247

d56c0d45f   Alexey Dobriyan   proc: decouple pr...
248
  		ioctl = pde->proc_ops->proc_ioctl;
866ad9a74   Al Viro   procfs: preparati...
249
250
251
  		if (ioctl)
  			rv = ioctl(file, cmd, arg);
  		unuse_pde(pde);
786d7e161   Alexey Dobriyan   Fix rmmod/read/wr...
252
  	}
786d7e161   Alexey Dobriyan   Fix rmmod/read/wr...
253
254
255
256
257
258
  	return rv;
  }
  
  #ifdef CONFIG_COMPAT
  static long proc_reg_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
  {
496ad9aa8   Al Viro   new helper: file_...
259
  	struct proc_dir_entry *pde = PDE(file_inode(file));
786d7e161   Alexey Dobriyan   Fix rmmod/read/wr...
260
  	long rv = -ENOTTY;
866ad9a74   Al Viro   procfs: preparati...
261
  	if (use_pde(pde)) {
d56c0d45f   Alexey Dobriyan   proc: decouple pr...
262
  		typeof_member(struct proc_ops, proc_compat_ioctl) compat_ioctl;
9af27b28b   Alexey Dobriyan   fs/proc/inode.c: ...
263

d56c0d45f   Alexey Dobriyan   proc: decouple pr...
264
  		compat_ioctl = pde->proc_ops->proc_compat_ioctl;
866ad9a74   Al Viro   procfs: preparati...
265
266
267
  		if (compat_ioctl)
  			rv = compat_ioctl(file, cmd, arg);
  		unuse_pde(pde);
786d7e161   Alexey Dobriyan   Fix rmmod/read/wr...
268
  	}
786d7e161   Alexey Dobriyan   Fix rmmod/read/wr...
269
270
271
272
273
274
  	return rv;
  }
  #endif
  
  static int proc_reg_mmap(struct file *file, struct vm_area_struct *vma)
  {
496ad9aa8   Al Viro   new helper: file_...
275
  	struct proc_dir_entry *pde = PDE(file_inode(file));
786d7e161   Alexey Dobriyan   Fix rmmod/read/wr...
276
  	int rv = -EIO;
866ad9a74   Al Viro   procfs: preparati...
277
  	if (use_pde(pde)) {
d56c0d45f   Alexey Dobriyan   proc: decouple pr...
278
  		typeof_member(struct proc_ops, proc_mmap) mmap;
9af27b28b   Alexey Dobriyan   fs/proc/inode.c: ...
279

d56c0d45f   Alexey Dobriyan   proc: decouple pr...
280
  		mmap = pde->proc_ops->proc_mmap;
866ad9a74   Al Viro   procfs: preparati...
281
282
283
  		if (mmap)
  			rv = mmap(file, vma);
  		unuse_pde(pde);
786d7e161   Alexey Dobriyan   Fix rmmod/read/wr...
284
  	}
786d7e161   Alexey Dobriyan   Fix rmmod/read/wr...
285
286
  	return rv;
  }
5721cf84d   HATAYAMA Daisuke   procfs: clean up ...
287
288
289
290
  static unsigned long
  proc_reg_get_unmapped_area(struct file *file, unsigned long orig_addr,
  			   unsigned long len, unsigned long pgoff,
  			   unsigned long flags)
c4fe24485   Alexey Dobriyan   sparc: fix PCI de...
291
292
  {
  	struct proc_dir_entry *pde = PDE(file_inode(file));
2cbe3b0af   HATAYAMA Daisuke   procfs: fix unint...
293
  	unsigned long rv = -EIO;
ae5758a1a   Jan Beulich   procfs: also fix ...
294

c4fe24485   Alexey Dobriyan   sparc: fix PCI de...
295
  	if (use_pde(pde)) {
d56c0d45f   Alexey Dobriyan   proc: decouple pr...
296
  		typeof_member(struct proc_ops, proc_get_unmapped_area) get_area;
ae5758a1a   Jan Beulich   procfs: also fix ...
297

d56c0d45f   Alexey Dobriyan   proc: decouple pr...
298
  		get_area = pde->proc_ops->proc_get_unmapped_area;
fad1a86e2   HATAYAMA Daisuke   procfs: call defa...
299
  #ifdef CONFIG_MMU
ae5758a1a   Jan Beulich   procfs: also fix ...
300
301
  		if (!get_area)
  			get_area = current->mm->get_unmapped_area;
fad1a86e2   HATAYAMA Daisuke   procfs: call defa...
302
  #endif
ae5758a1a   Jan Beulich   procfs: also fix ...
303

5721cf84d   HATAYAMA Daisuke   procfs: clean up ...
304
305
  		if (get_area)
  			rv = get_area(file, orig_addr, len, pgoff, flags);
ae5758a1a   Jan Beulich   procfs: also fix ...
306
307
  		else
  			rv = orig_addr;
c4fe24485   Alexey Dobriyan   sparc: fix PCI de...
308
309
310
311
  		unuse_pde(pde);
  	}
  	return rv;
  }
786d7e161   Alexey Dobriyan   Fix rmmod/read/wr...
312
313
314
315
  static int proc_reg_open(struct inode *inode, struct file *file)
  {
  	struct proc_dir_entry *pde = PDE(inode);
  	int rv = 0;
d56c0d45f   Alexey Dobriyan   proc: decouple pr...
316
317
  	typeof_member(struct proc_ops, proc_open) open;
  	typeof_member(struct proc_ops, proc_release) release;
881adb853   Alexey Dobriyan   proc: always do -...
318
319
320
  	struct pde_opener *pdeo;
  
  	/*
492b2da60   Alexey Dobriyan   proc: tweak comme...
321
322
323
324
325
326
327
  	 * 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 -...
328
  	 *
492b2da60   Alexey Dobriyan   proc: tweak comme...
329
  	 * Save every "struct file" with custom ->release hook.
881adb853   Alexey Dobriyan   proc: always do -...
330
  	 */
e7a6e291e   Alexey Dobriyan   proc: faster open...
331
  	if (!use_pde(pde))
d2857e79a   Daisuke Ogino   procfs: return EN...
332
  		return -ENOENT;
e7a6e291e   Alexey Dobriyan   proc: faster open...
333

d56c0d45f   Alexey Dobriyan   proc: decouple pr...
334
  	release = pde->proc_ops->proc_release;
e7a6e291e   Alexey Dobriyan   proc: faster open...
335
  	if (release) {
195b8cf06   Alexey Dobriyan   proc: move "struc...
336
  		pdeo = kmem_cache_alloc(pde_opener_cache, GFP_KERNEL);
e7a6e291e   Alexey Dobriyan   proc: faster open...
337
338
339
340
341
  		if (!pdeo) {
  			rv = -ENOMEM;
  			goto out_unuse;
  		}
  	}
786d7e161   Alexey Dobriyan   Fix rmmod/read/wr...
342

d56c0d45f   Alexey Dobriyan   proc: decouple pr...
343
  	open = pde->proc_ops->proc_open;
786d7e161   Alexey Dobriyan   Fix rmmod/read/wr...
344
345
  	if (open)
  		rv = open(inode, file);
e7a6e291e   Alexey Dobriyan   proc: faster open...
346
347
348
349
350
351
352
353
354
355
  	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...
356
  			kmem_cache_free(pde_opener_cache, pdeo);
e7a6e291e   Alexey Dobriyan   proc: faster open...
357
  	}
05c0ae21c   Al Viro   try a saner locki...
358

e7a6e291e   Alexey Dobriyan   proc: faster open...
359
  out_unuse:
05c0ae21c   Al Viro   try a saner locki...
360
  	unuse_pde(pde);
786d7e161   Alexey Dobriyan   Fix rmmod/read/wr...
361
362
363
364
365
366
  	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 -...
367
  	struct pde_opener *pdeo;
786d7e161   Alexey Dobriyan   Fix rmmod/read/wr...
368
  	spin_lock(&pde->pde_unload_lock);
ca469f35a   Al Viro   deal with races b...
369
370
371
  	list_for_each_entry(pdeo, &pde->pde_openers, lh) {
  		if (pdeo->file == file) {
  			close_pdeo(pde, pdeo);
2f8974243   Alexey Dobriyan   proc: do less stu...
372
  			return 0;
ca469f35a   Al Viro   deal with races b...
373
  		}
881adb853   Alexey Dobriyan   proc: always do -...
374
  	}
786d7e161   Alexey Dobriyan   Fix rmmod/read/wr...
375
  	spin_unlock(&pde->pde_unload_lock);
ca469f35a   Al Viro   deal with races b...
376
  	return 0;
786d7e161   Alexey Dobriyan   Fix rmmod/read/wr...
377
378
379
380
381
382
383
384
385
386
387
388
  }
  
  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,
  #ifdef CONFIG_COMPAT
  	.compat_ioctl	= proc_reg_compat_ioctl,
  #endif
  	.mmap		= proc_reg_mmap,
c4fe24485   Alexey Dobriyan   sparc: fix PCI de...
389
  	.get_unmapped_area = proc_reg_get_unmapped_area,
786d7e161   Alexey Dobriyan   Fix rmmod/read/wr...
390
391
392
  	.open		= proc_reg_open,
  	.release	= proc_reg_release,
  };
778f3dd5a   David Miller   Fix procfs compat...
393
394
395
396
397
398
399
400
  #ifdef CONFIG_COMPAT
  static const struct file_operations proc_reg_file_ops_no_compat = {
  	.llseek		= proc_reg_llseek,
  	.read		= proc_reg_read,
  	.write		= proc_reg_write,
  	.poll		= proc_reg_poll,
  	.unlocked_ioctl	= proc_reg_unlocked_ioctl,
  	.mmap		= proc_reg_mmap,
c4fe24485   Alexey Dobriyan   sparc: fix PCI de...
401
  	.get_unmapped_area = proc_reg_get_unmapped_area,
778f3dd5a   David Miller   Fix procfs compat...
402
403
404
405
  	.open		= proc_reg_open,
  	.release	= proc_reg_release,
  };
  #endif
fceef393a   Al Viro   switch ->get_link...
406
407
408
409
  static void proc_put_link(void *p)
  {
  	unuse_pde(p);
  }
6b2553918   Al Viro   replace ->follow_...
410
  static const char *proc_get_link(struct dentry *dentry,
fceef393a   Al Viro   switch ->get_link...
411
412
  				 struct inode *inode,
  				 struct delayed_call *done)
7e0e953bb   Al Viro   procfs: fix race ...
413
  {
6b2553918   Al Viro   replace ->follow_...
414
  	struct proc_dir_entry *pde = PDE(inode);
15b158b4e   Alexey Dobriyan   proc: spread like...
415
  	if (!use_pde(pde))
7e0e953bb   Al Viro   procfs: fix race ...
416
  		return ERR_PTR(-EINVAL);
fceef393a   Al Viro   switch ->get_link...
417
  	set_delayed_call(done, proc_put_link, pde);
680baacbc   Al Viro   new ->follow_link...
418
  	return pde->data;
7e0e953bb   Al Viro   procfs: fix race ...
419
  }
7e0e953bb   Al Viro   procfs: fix race ...
420
  const struct inode_operations proc_link_inode_operations = {
6b2553918   Al Viro   replace ->follow_...
421
  	.get_link	= proc_get_link,
7e0e953bb   Al Viro   procfs: fix race ...
422
  };
6d1b6e4ef   Alexey Dobriyan   proc: ->low_ino c...
423
  struct inode *proc_get_inode(struct super_block *sb, struct proc_dir_entry *de)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
424
  {
51f0885e5   Linus Torvalds   vfs,proc: guarant...
425
  	struct inode *inode = new_inode_pseudo(sb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
426

51f0885e5   Linus Torvalds   vfs,proc: guarant...
427
428
  	if (inode) {
  		inode->i_ino = de->low_ino;
078cd8279   Deepa Dinamani   fs: Replace CURRE...
429
  		inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode);
a1d4aebbf   David Howells   iget: stop PROCFS...
430
  		PROC_I(inode)->pde = de;
5e971dce0   Alexey Dobriyan   proc: drop severa...
431

eb6d38d54   Eric W. Biederman   proc: Allow creat...
432
433
434
435
  		if (is_empty_pde(de)) {
  			make_empty_dir_inode(inode);
  			return inode;
  		}
5e971dce0   Alexey Dobriyan   proc: drop severa...
436
437
438
439
440
441
442
443
  		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)
bfe868486   Miklos Szeredi   filesystems: add ...
444
  			set_nlink(inode, de->nlink);
d56c0d45f   Alexey Dobriyan   proc: decouple pr...
445
446
447
448
  
  		if (S_ISREG(inode->i_mode)) {
  			inode->i_op = de->proc_iops;
  			inode->i_fop = &proc_reg_file_ops;
778f3dd5a   David Miller   Fix procfs compat...
449
  #ifdef CONFIG_COMPAT
d56c0d45f   Alexey Dobriyan   proc: decouple pr...
450
451
  			if (!de->proc_ops->proc_compat_ioctl) {
  				inode->i_fop = &proc_reg_file_ops_no_compat;
778f3dd5a   David Miller   Fix procfs compat...
452
  			}
d56c0d45f   Alexey Dobriyan   proc: decouple pr...
453
454
455
456
457
458
459
460
461
  #endif
  		} 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();
99b762338   Alexey Dobriyan   proc 2/2: remove ...
462
  	} else
135d5655d   Alexey Dobriyan   proc: rename de_g...
463
  	       pde_put(de);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
464
  	return inode;
d3d009cb9   Al Viro   saner proc_get_in...
465
  }