inode.c 12.2 KB
Newer Older
Linus Torvalds's avatar
Linus Torvalds committed
1
2
3
4
5
6
7
8
9
10
11
12
/*
 *  linux/fs/proc/inode.c
 *
 *  Copyright (C) 1991, 1992  Linus Torvalds
 */

#include <linux/time.h>
#include <linux/proc_fs.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/string.h>
#include <linux/stat.h>
13
#include <linux/completion.h>
14
#include <linux/poll.h>
Linus Torvalds's avatar
Linus Torvalds committed
15
16
17
18
19
#include <linux/file.h>
#include <linux/limits.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/smp_lock.h>
Al Viro's avatar
Al Viro committed
20
#include <linux/sysctl.h>
Linus Torvalds's avatar
Linus Torvalds committed
21
22
23
24

#include <asm/system.h>
#include <asm/uaccess.h>

25
#include "internal.h"
Linus Torvalds's avatar
Linus Torvalds committed
26

27
struct proc_dir_entry *de_get(struct proc_dir_entry *de)
Linus Torvalds's avatar
Linus Torvalds committed
28
{
29
	atomic_inc(&de->count);
Linus Torvalds's avatar
Linus Torvalds committed
30
31
32
33
34
35
	return de;
}

/*
 * Decrements the use count and checks for deferred deletion.
 */
36
void de_put(struct proc_dir_entry *de)
Linus Torvalds's avatar
Linus Torvalds committed
37
{
38
39
40
	if (!atomic_read(&de->count)) {
		printk("de_put: entry %s already free!\n", de->name);
		return;
Linus Torvalds's avatar
Linus Torvalds committed
41
	}
42
43
44

	if (atomic_dec_and_test(&de->count))
		free_proc_entry(de);
Linus Torvalds's avatar
Linus Torvalds committed
45
46
47
48
49
50
51
52
53
}

/*
 * Decrement the use count of the proc_dir_entry.
 */
static void proc_delete_inode(struct inode *inode)
{
	struct proc_dir_entry *de;

54
55
	truncate_inode_pages(&inode->i_data, 0);

56
	/* Stop tracking associated processes */
57
	put_pid(PROC_I(inode)->pid);
Linus Torvalds's avatar
Linus Torvalds committed
58
59
60
61
62
63
64
65

	/* Let go of any associated proc directory entry */
	de = PROC_I(inode)->pde;
	if (de) {
		if (de->owner)
			module_put(de->owner);
		de_put(de);
	}
Al Viro's avatar
Al Viro committed
66
67
	if (PROC_I(inode)->sysctl)
		sysctl_head_put(PROC_I(inode)->sysctl);
Linus Torvalds's avatar
Linus Torvalds committed
68
69
70
71
72
	clear_inode(inode);
}

struct vfsmount *proc_mnt;

73
static struct kmem_cache * proc_inode_cachep;
Linus Torvalds's avatar
Linus Torvalds committed
74
75
76
77
78
79

static struct inode *proc_alloc_inode(struct super_block *sb)
{
	struct proc_inode *ei;
	struct inode *inode;

80
	ei = (struct proc_inode *)kmem_cache_alloc(proc_inode_cachep, GFP_KERNEL);
Linus Torvalds's avatar
Linus Torvalds committed
81
82
	if (!ei)
		return NULL;
83
	ei->pid = NULL;
84
	ei->fd = 0;
Linus Torvalds's avatar
Linus Torvalds committed
85
86
	ei->op.proc_get_link = NULL;
	ei->pde = NULL;
Al Viro's avatar
Al Viro committed
87
88
	ei->sysctl = NULL;
	ei->sysctl_entry = NULL;
Linus Torvalds's avatar
Linus Torvalds committed
89
90
91
92
93
94
95
96
97
98
	inode = &ei->vfs_inode;
	inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
	return inode;
}

static void proc_destroy_inode(struct inode *inode)
{
	kmem_cache_free(proc_inode_cachep, PROC_I(inode));
}

99
static void init_once(void *foo)
Linus Torvalds's avatar
Linus Torvalds committed
100
101
102
{
	struct proc_inode *ei = (struct proc_inode *) foo;

103
	inode_init_once(&ei->vfs_inode);
Linus Torvalds's avatar
Linus Torvalds committed
104
}
105

106
void __init proc_init_inodecache(void)
Linus Torvalds's avatar
Linus Torvalds committed
107
108
109
{
	proc_inode_cachep = kmem_cache_create("proc_inode_cache",
					     sizeof(struct proc_inode),
110
					     0, (SLAB_RECLAIM_ACCOUNT|
111
						SLAB_MEM_SPREAD|SLAB_PANIC),
112
					     init_once);
Linus Torvalds's avatar
Linus Torvalds committed
113
114
}

115
static const struct super_operations proc_sops = {
Linus Torvalds's avatar
Linus Torvalds committed
116
117
118
119
120
121
122
	.alloc_inode	= proc_alloc_inode,
	.destroy_inode	= proc_destroy_inode,
	.drop_inode	= generic_delete_inode,
	.delete_inode	= proc_delete_inode,
	.statfs		= simple_statfs,
};

Alexey Dobriyan's avatar
Alexey Dobriyan committed
123
static void __pde_users_dec(struct proc_dir_entry *pde)
124
125
126
127
{
	pde->pde_users--;
	if (pde->pde_unload_completion && pde->pde_users == 0)
		complete(pde->pde_unload_completion);
Alexey Dobriyan's avatar
Alexey Dobriyan committed
128
129
}

130
void pde_users_dec(struct proc_dir_entry *pde)
Alexey Dobriyan's avatar
Alexey Dobriyan committed
131
132
133
{
	spin_lock(&pde->pde_unload_lock);
	__pde_users_dec(pde);
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
	spin_unlock(&pde->pde_unload_lock);
}

static loff_t proc_reg_llseek(struct file *file, loff_t offset, int whence)
{
	struct proc_dir_entry *pde = PDE(file->f_path.dentry->d_inode);
	loff_t rv = -EINVAL;
	loff_t (*llseek)(struct file *, loff_t, int);

	spin_lock(&pde->pde_unload_lock);
	/*
	 * remove_proc_entry() is going to delete PDE (as part of module
	 * cleanup sequence). No new callers into module allowed.
	 */
	if (!pde->proc_fops) {
		spin_unlock(&pde->pde_unload_lock);
		return rv;
	}
	/*
	 * Bump refcount so that remove_proc_entry will wail for ->llseek to
	 * complete.
	 */
	pde->pde_users++;
	/*
	 * Save function pointer under lock, to protect against ->proc_fops
	 * NULL'ifying right after ->pde_unload_lock is dropped.
	 */
	llseek = pde->proc_fops->llseek;
	spin_unlock(&pde->pde_unload_lock);

	if (!llseek)
		llseek = default_llseek;
	rv = llseek(file, offset, whence);

	pde_users_dec(pde);
	return rv;
}

static ssize_t proc_reg_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
{
	struct proc_dir_entry *pde = PDE(file->f_path.dentry->d_inode);
	ssize_t rv = -EIO;
	ssize_t (*read)(struct file *, char __user *, size_t, loff_t *);

	spin_lock(&pde->pde_unload_lock);
	if (!pde->proc_fops) {
		spin_unlock(&pde->pde_unload_lock);
		return rv;
	}
	pde->pde_users++;
	read = pde->proc_fops->read;
	spin_unlock(&pde->pde_unload_lock);

	if (read)
		rv = read(file, buf, count, ppos);

	pde_users_dec(pde);
	return rv;
}

static ssize_t proc_reg_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
{
	struct proc_dir_entry *pde = PDE(file->f_path.dentry->d_inode);
	ssize_t rv = -EIO;
	ssize_t (*write)(struct file *, const char __user *, size_t, loff_t *);

	spin_lock(&pde->pde_unload_lock);
	if (!pde->proc_fops) {
		spin_unlock(&pde->pde_unload_lock);
		return rv;
	}
	pde->pde_users++;
	write = pde->proc_fops->write;
	spin_unlock(&pde->pde_unload_lock);

	if (write)
		rv = write(file, buf, count, ppos);

	pde_users_dec(pde);
	return rv;
}

static unsigned int proc_reg_poll(struct file *file, struct poll_table_struct *pts)
{
	struct proc_dir_entry *pde = PDE(file->f_path.dentry->d_inode);
219
	unsigned int rv = DEFAULT_POLLMASK;
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
	unsigned int (*poll)(struct file *, struct poll_table_struct *);

	spin_lock(&pde->pde_unload_lock);
	if (!pde->proc_fops) {
		spin_unlock(&pde->pde_unload_lock);
		return rv;
	}
	pde->pde_users++;
	poll = pde->proc_fops->poll;
	spin_unlock(&pde->pde_unload_lock);

	if (poll)
		rv = poll(file, pts);

	pde_users_dec(pde);
	return rv;
}

static long proc_reg_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
	struct proc_dir_entry *pde = PDE(file->f_path.dentry->d_inode);
	long rv = -ENOTTY;
	long (*unlocked_ioctl)(struct file *, unsigned int, unsigned long);
	int (*ioctl)(struct inode *, struct file *, unsigned int, unsigned long);

	spin_lock(&pde->pde_unload_lock);
	if (!pde->proc_fops) {
		spin_unlock(&pde->pde_unload_lock);
		return rv;
	}
	pde->pde_users++;
	unlocked_ioctl = pde->proc_fops->unlocked_ioctl;
	ioctl = pde->proc_fops->ioctl;
	spin_unlock(&pde->pde_unload_lock);

	if (unlocked_ioctl) {
		rv = unlocked_ioctl(file, cmd, arg);
		if (rv == -ENOIOCTLCMD)
			rv = -EINVAL;
	} else if (ioctl) {
		lock_kernel();
		rv = ioctl(file->f_path.dentry->d_inode, file, cmd, arg);
		unlock_kernel();
	}

	pde_users_dec(pde);
	return rv;
}

#ifdef CONFIG_COMPAT
static long proc_reg_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
	struct proc_dir_entry *pde = PDE(file->f_path.dentry->d_inode);
	long rv = -ENOTTY;
	long (*compat_ioctl)(struct file *, unsigned int, unsigned long);

	spin_lock(&pde->pde_unload_lock);
	if (!pde->proc_fops) {
		spin_unlock(&pde->pde_unload_lock);
		return rv;
	}
	pde->pde_users++;
	compat_ioctl = pde->proc_fops->compat_ioctl;
	spin_unlock(&pde->pde_unload_lock);

	if (compat_ioctl)
		rv = compat_ioctl(file, cmd, arg);

	pde_users_dec(pde);
	return rv;
}
#endif

static int proc_reg_mmap(struct file *file, struct vm_area_struct *vma)
{
	struct proc_dir_entry *pde = PDE(file->f_path.dentry->d_inode);
	int rv = -EIO;
	int (*mmap)(struct file *, struct vm_area_struct *);

	spin_lock(&pde->pde_unload_lock);
	if (!pde->proc_fops) {
		spin_unlock(&pde->pde_unload_lock);
		return rv;
	}
	pde->pde_users++;
	mmap = pde->proc_fops->mmap;
	spin_unlock(&pde->pde_unload_lock);

	if (mmap)
		rv = mmap(file, vma);

	pde_users_dec(pde);
	return rv;
}

static int proc_reg_open(struct inode *inode, struct file *file)
{
	struct proc_dir_entry *pde = PDE(inode);
	int rv = 0;
	int (*open)(struct inode *, struct file *);
Alexey Dobriyan's avatar
Alexey Dobriyan committed
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
	int (*release)(struct inode *, struct file *);
	struct pde_opener *pdeo;

	/*
	 * What for, you ask? Well, we can have open, rmmod, remove_proc_entry
	 * sequence. ->release won't be called because ->proc_fops will be
	 * cleared. Depending on complexity of ->release, consequences vary.
	 *
	 * We can't wait for mercy when close will be done for real, it's
	 * deadlockable: rmmod foo </proc/foo . So, we're going to do ->release
	 * by hand in remove_proc_entry(). For this, save opener's credentials
	 * for later.
	 */
	pdeo = kmalloc(sizeof(struct pde_opener), GFP_KERNEL);
	if (!pdeo)
		return -ENOMEM;
336
337
338
339

	spin_lock(&pde->pde_unload_lock);
	if (!pde->proc_fops) {
		spin_unlock(&pde->pde_unload_lock);
Alexey Dobriyan's avatar
Alexey Dobriyan committed
340
		kfree(pdeo);
341
		return -EINVAL;
342
343
344
	}
	pde->pde_users++;
	open = pde->proc_fops->open;
Alexey Dobriyan's avatar
Alexey Dobriyan committed
345
	release = pde->proc_fops->release;
346
347
348
349
350
	spin_unlock(&pde->pde_unload_lock);

	if (open)
		rv = open(inode, file);

Alexey Dobriyan's avatar
Alexey Dobriyan committed
351
352
353
354
355
356
357
358
359
360
361
362
	spin_lock(&pde->pde_unload_lock);
	if (rv == 0 && release) {
		/* To know what to release. */
		pdeo->inode = inode;
		pdeo->file = file;
		/* Strictly for "too late" ->release in proc_reg_release(). */
		pdeo->release = release;
		list_add(&pdeo->lh, &pde->pde_openers);
	} else
		kfree(pdeo);
	__pde_users_dec(pde);
	spin_unlock(&pde->pde_unload_lock);
363
364
365
	return rv;
}

Alexey Dobriyan's avatar
Alexey Dobriyan committed
366
367
368
369
370
371
372
373
374
375
376
377
static struct pde_opener *find_pde_opener(struct proc_dir_entry *pde,
					struct inode *inode, struct file *file)
{
	struct pde_opener *pdeo;

	list_for_each_entry(pdeo, &pde->pde_openers, lh) {
		if (pdeo->inode == inode && pdeo->file == file)
			return pdeo;
	}
	return NULL;
}

378
379
380
381
382
static int proc_reg_release(struct inode *inode, struct file *file)
{
	struct proc_dir_entry *pde = PDE(inode);
	int rv = 0;
	int (*release)(struct inode *, struct file *);
Alexey Dobriyan's avatar
Alexey Dobriyan committed
383
	struct pde_opener *pdeo;
384
385

	spin_lock(&pde->pde_unload_lock);
Alexey Dobriyan's avatar
Alexey Dobriyan committed
386
	pdeo = find_pde_opener(pde, inode, file);
387
	if (!pde->proc_fops) {
Alexey Dobriyan's avatar
Alexey Dobriyan committed
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
		/*
		 * Can't simply exit, __fput() will think that everything is OK,
		 * and move on to freeing struct file. remove_proc_entry() will
		 * find slacker in opener's list and will try to do non-trivial
		 * things with struct file. Therefore, remove opener from list.
		 *
		 * But if opener is removed from list, who will ->release it?
		 */
		if (pdeo) {
			list_del(&pdeo->lh);
			spin_unlock(&pde->pde_unload_lock);
			rv = pdeo->release(inode, file);
			kfree(pdeo);
		} else
			spin_unlock(&pde->pde_unload_lock);
403
404
405
406
		return rv;
	}
	pde->pde_users++;
	release = pde->proc_fops->release;
Alexey Dobriyan's avatar
Alexey Dobriyan committed
407
408
409
410
	if (pdeo) {
		list_del(&pdeo->lh);
		kfree(pdeo);
	}
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
	spin_unlock(&pde->pde_unload_lock);

	if (release)
		rv = release(inode, file);

	pde_users_dec(pde);
	return rv;
}

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,
	.open		= proc_reg_open,
	.release	= proc_reg_release,
};

434
435
436
437
438
439
440
441
442
443
444
445
446
#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,
	.open		= proc_reg_open,
	.release	= proc_reg_release,
};
#endif

Linus Torvalds's avatar
Linus Torvalds committed
447
448
449
450
451
struct inode *proc_get_inode(struct super_block *sb, unsigned int ino,
				struct proc_dir_entry *de)
{
	struct inode * inode;

452
	if (!try_module_get(de->owner))
453
454
		goto out_mod;

455
	inode = iget_locked(sb, ino);
Linus Torvalds's avatar
Linus Torvalds committed
456
	if (!inode)
457
		goto out_ino;
458
459
460
461
	if (inode->i_state & I_NEW) {
		inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
		PROC_I(inode)->fd = 0;
		PROC_I(inode)->pde = de;
462
463
464
465
466
467
468
469
470
471
472
473
474
475

		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)
			inode->i_nlink = de->nlink;
		if (de->proc_iops)
			inode->i_op = de->proc_iops;
		if (de->proc_fops) {
			if (S_ISREG(inode->i_mode)) {
476
#ifdef CONFIG_COMPAT
477
478
479
480
				if (!de->proc_fops->compat_ioctl)
					inode->i_fop =
						&proc_reg_file_ops_no_compat;
				else
481
#endif
482
483
484
					inode->i_fop = &proc_reg_file_ops;
			} else {
				inode->i_fop = de->proc_fops;
485
			}
486
		}
487
		unlock_new_inode(inode);
488
	} else {
489
	       module_put(de->owner);
490
491
	       de_put(de);
	}
Linus Torvalds's avatar
Linus Torvalds committed
492
493
	return inode;

494
out_ino:
495
	module_put(de->owner);
496
497
out_mod:
	return NULL;
Linus Torvalds's avatar
Linus Torvalds committed
498
499
}			

500
int proc_fill_super(struct super_block *s)
Linus Torvalds's avatar
Linus Torvalds committed
501
502
503
{
	struct inode * root_inode;

504
	s->s_flags |= MS_NODIRATIME | MS_NOSUID | MS_NOEXEC;
Linus Torvalds's avatar
Linus Torvalds committed
505
506
507
508
509
510
	s->s_blocksize = 1024;
	s->s_blocksize_bits = 10;
	s->s_magic = PROC_SUPER_MAGIC;
	s->s_op = &proc_sops;
	s->s_time_gran = 1;
	
511
	de_get(&proc_root);
Linus Torvalds's avatar
Linus Torvalds committed
512
513
514
515
516
517
518
519
520
521
522
523
524
	root_inode = proc_get_inode(s, PROC_ROOT_INO, &proc_root);
	if (!root_inode)
		goto out_no_root;
	root_inode->i_uid = 0;
	root_inode->i_gid = 0;
	s->s_root = d_alloc_root(root_inode);
	if (!s->s_root)
		goto out_no_root;
	return 0;

out_no_root:
	printk("proc_read_super: get root inode failed\n");
	iput(root_inode);
525
	de_put(&proc_root);
Linus Torvalds's avatar
Linus Torvalds committed
526
527
	return -ENOMEM;
}