Blame view

fs/proc/generic.c 19.4 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
  /*
   * proc/fs/generic.c --- generic routines for the proc-fs
   *
   * This file contains generic proc-fs routines for handling
   * directories and files.
   * 
   * Copyright (C) 1991, 1992 Linus Torvalds.
   * Copyright (C) 1997 Theodore Ts'o
   */
  
  #include <linux/errno.h>
  #include <linux/time.h>
  #include <linux/proc_fs.h>
  #include <linux/stat.h>
1025774ce   Christoph Hellwig   remove inode_setattr
15
  #include <linux/mm.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
16
  #include <linux/module.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
17
  #include <linux/slab.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
18
  #include <linux/mount.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
19
20
21
22
  #include <linux/init.h>
  #include <linux/idr.h>
  #include <linux/namei.h>
  #include <linux/bitops.h>
64a07bd82   Steven Rostedt   [PATCH] protect r...
23
  #include <linux/spinlock.h>
786d7e161   Alexey Dobriyan   Fix rmmod/read/wr...
24
  #include <linux/completion.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
25
  #include <asm/uaccess.h>
fee781e6c   Adrian Bunk   [PATCH] fs/proc/:...
26
  #include "internal.h"
64a07bd82   Steven Rostedt   [PATCH] protect r...
27
  DEFINE_SPINLOCK(proc_subdir_lock);
312ec7e50   Alexey Dobriyan   proc: make struct...
28
  static int proc_match(unsigned int len, const char *name, struct proc_dir_entry *de)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
29
30
31
32
33
  {
  	if (de->namelen != len)
  		return 0;
  	return !memcmp(name, de->name, len);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
34
35
36
37
  /* buffer size is one page but our output routines use some slack for overruns */
  #define PROC_BLOCK_SIZE	(PAGE_SIZE - 1024)
  
  static ssize_t
3dec7f59c   Alexey Dobriyan   proc 1/2: do PDE ...
38
  __proc_file_read(struct file *file, char __user *buf, size_t nbytes,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
39
40
  	       loff_t *ppos)
  {
2fddfeefe   Josef "Jeff" Sipek   [PATCH] proc: cha...
41
  	struct inode * inode = file->f_path.dentry->d_inode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
42
43
44
45
46
47
  	char 	*page;
  	ssize_t	retval=0;
  	int	eof=0;
  	ssize_t	n, count;
  	char	*start;
  	struct proc_dir_entry * dp;
8b90db0df   Linus Torvalds   Insanity avoidanc...
48
49
50
51
52
53
54
55
56
57
58
59
  	unsigned long long pos;
  
  	/*
  	 * Gaah, please just use "seq_file" instead. The legacy /proc
  	 * interfaces cut loff_t down to off_t for reads, and ignore
  	 * the offset entirely for writes..
  	 */
  	pos = *ppos;
  	if (pos > MAX_NON_LFS)
  		return 0;
  	if (nbytes > MAX_NON_LFS - pos)
  		nbytes = MAX_NON_LFS - pos;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
60
61
  
  	dp = PDE(inode);
e12ba74d8   Mel Gorman   Group short-lived...
62
  	if (!(page = (char*) __get_free_page(GFP_TEMPORARY)))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
63
64
65
66
67
68
  		return -ENOMEM;
  
  	while ((nbytes > 0) && !eof) {
  		count = min_t(size_t, PROC_BLOCK_SIZE, nbytes);
  
  		start = NULL;
8731f14d3   Alexey Dobriyan   proc: remove ->ge...
69
  		if (dp->read_proc) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
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
  			/*
  			 * How to be a proc read function
  			 * ------------------------------
  			 * Prototype:
  			 *    int f(char *buffer, char **start, off_t offset,
  			 *          int count, int *peof, void *dat)
  			 *
  			 * Assume that the buffer is "count" bytes in size.
  			 *
  			 * If you know you have supplied all the data you
  			 * have, set *peof.
  			 *
  			 * You have three ways to return data:
  			 * 0) Leave *start = NULL.  (This is the default.)
  			 *    Put the data of the requested offset at that
  			 *    offset within the buffer.  Return the number (n)
  			 *    of bytes there are from the beginning of the
  			 *    buffer up to the last byte of data.  If the
  			 *    number of supplied bytes (= n - offset) is 
  			 *    greater than zero and you didn't signal eof
  			 *    and the reader is prepared to take more data
  			 *    you will be called again with the requested
  			 *    offset advanced by the number of bytes 
  			 *    absorbed.  This interface is useful for files
  			 *    no larger than the buffer.
  			 * 1) Set *start = an unsigned long value less than
  			 *    the buffer address but greater than zero.
  			 *    Put the data of the requested offset at the
  			 *    beginning of the buffer.  Return the number of
  			 *    bytes of data placed there.  If this number is
  			 *    greater than zero and you didn't signal eof
  			 *    and the reader is prepared to take more data
  			 *    you will be called again with the requested
  			 *    offset advanced by *start.  This interface is
  			 *    useful when you have a large file consisting
  			 *    of a series of blocks which you want to count
  			 *    and return as wholes.
  			 *    (Hack by Paul.Russell@rustcorp.com.au)
  			 * 2) Set *start = an address within the buffer.
  			 *    Put the data of the requested offset at *start.
  			 *    Return the number of bytes of data placed there.
  			 *    If this number is greater than zero and you
  			 *    didn't signal eof and the reader is prepared to
  			 *    take more data you will be called again with the
  			 *    requested offset advanced by the number of bytes
  			 *    absorbed.
  			 */
  			n = dp->read_proc(page, &start, *ppos,
  					  count, &eof, dp->data);
  		} else
  			break;
  
  		if (n == 0)   /* end of file */
  			break;
  		if (n < 0) {  /* error */
  			if (retval == 0)
  				retval = n;
  			break;
  		}
  
  		if (start == NULL) {
  			if (n > PAGE_SIZE) {
  				printk(KERN_ERR
  				       "proc_file_read: Apparent buffer overflow!
  ");
  				n = PAGE_SIZE;
  			}
  			n -= *ppos;
  			if (n <= 0)
  				break;
  			if (n > count)
  				n = count;
  			start = page + *ppos;
  		} else if (start < page) {
  			if (n > PAGE_SIZE) {
  				printk(KERN_ERR
  				       "proc_file_read: Apparent buffer overflow!
  ");
  				n = PAGE_SIZE;
  			}
  			if (n > count) {
  				/*
  				 * Don't reduce n because doing so might
  				 * cut off part of a data block.
  				 */
  				printk(KERN_WARNING
  				       "proc_file_read: Read count exceeded
  ");
  			}
  		} else /* start >= page */ {
  			unsigned long startoff = (unsigned long)(start - page);
  			if (n > (PAGE_SIZE - startoff)) {
  				printk(KERN_ERR
  				       "proc_file_read: Apparent buffer overflow!
  ");
  				n = PAGE_SIZE - startoff;
  			}
  			if (n > count)
  				n = count;
  		}
  		
   		n -= copy_to_user(buf, start < page ? page : start, n);
  		if (n == 0) {
  			if (retval == 0)
  				retval = -EFAULT;
  			break;
  		}
  
  		*ppos += start < page ? (unsigned long)start : n;
  		nbytes -= n;
  		buf += n;
  		retval += n;
  	}
  	free_page((unsigned long) page);
  	return retval;
  }
  
  static ssize_t
3dec7f59c   Alexey Dobriyan   proc 1/2: do PDE ...
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
  proc_file_read(struct file *file, char __user *buf, size_t nbytes,
  	       loff_t *ppos)
  {
  	struct proc_dir_entry *pde = PDE(file->f_path.dentry->d_inode);
  	ssize_t rv = -EIO;
  
  	spin_lock(&pde->pde_unload_lock);
  	if (!pde->proc_fops) {
  		spin_unlock(&pde->pde_unload_lock);
  		return rv;
  	}
  	pde->pde_users++;
  	spin_unlock(&pde->pde_unload_lock);
  
  	rv = __proc_file_read(file, buf, nbytes, ppos);
  
  	pde_users_dec(pde);
  	return rv;
  }
  
  static ssize_t
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
209
210
211
  proc_file_write(struct file *file, const char __user *buffer,
  		size_t count, loff_t *ppos)
  {
3dec7f59c   Alexey Dobriyan   proc 1/2: do PDE ...
212
213
214
215
216
217
218
219
220
221
222
  	struct proc_dir_entry *pde = PDE(file->f_path.dentry->d_inode);
  	ssize_t rv = -EIO;
  
  	if (pde->write_proc) {
  		spin_lock(&pde->pde_unload_lock);
  		if (!pde->proc_fops) {
  			spin_unlock(&pde->pde_unload_lock);
  			return rv;
  		}
  		pde->pde_users++;
  		spin_unlock(&pde->pde_unload_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
223

3dec7f59c   Alexey Dobriyan   proc 1/2: do PDE ...
224
225
226
227
228
  		/* FIXME: does this routine need ppos?  probably... */
  		rv = pde->write_proc(file, buffer, count, pde->data);
  		pde_users_dec(pde);
  	}
  	return rv;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
229
230
231
232
233
234
  }
  
  
  static loff_t
  proc_file_lseek(struct file *file, loff_t offset, int orig)
  {
8b90db0df   Linus Torvalds   Insanity avoidanc...
235
236
237
238
239
240
241
242
243
244
245
  	loff_t retval = -EINVAL;
  	switch (orig) {
  	case 1:
  		offset += file->f_pos;
  	/* fallthrough */
  	case 0:
  		if (offset < 0 || offset > MAX_NON_LFS)
  			break;
  		file->f_pos = retval = offset;
  	}
  	return retval;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
246
  }
76df0c25d   Alexey Dobriyan   proc: simplify fu...
247
248
249
250
251
  static const struct file_operations proc_file_operations = {
  	.llseek		= proc_file_lseek,
  	.read		= proc_file_read,
  	.write		= proc_file_write,
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
252
253
254
255
256
257
258
259
  static int proc_notify_change(struct dentry *dentry, struct iattr *iattr)
  {
  	struct inode *inode = dentry->d_inode;
  	struct proc_dir_entry *de = PDE(inode);
  	int error;
  
  	error = inode_change_ok(inode, iattr);
  	if (error)
1025774ce   Christoph Hellwig   remove inode_setattr
260
  		return error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
261

1025774ce   Christoph Hellwig   remove inode_setattr
262
263
264
265
266
267
268
269
270
  	if ((iattr->ia_valid & ATTR_SIZE) &&
  	    iattr->ia_size != i_size_read(inode)) {
  		error = vmtruncate(inode, iattr->ia_size);
  		if (error)
  			return error;
  	}
  
  	setattr_copy(inode, iattr);
  	mark_inode_dirty(inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
271
272
273
274
  	
  	de->uid = inode->i_uid;
  	de->gid = inode->i_gid;
  	de->mode = inode->i_mode;
1025774ce   Christoph Hellwig   remove inode_setattr
275
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
276
  }
2b579beec   Miklos Szeredi   [PATCH] proc: lin...
277
278
279
280
281
282
  static int proc_getattr(struct vfsmount *mnt, struct dentry *dentry,
  			struct kstat *stat)
  {
  	struct inode *inode = dentry->d_inode;
  	struct proc_dir_entry *de = PROC_I(inode)->pde;
  	if (de && de->nlink)
bfe868486   Miklos Szeredi   filesystems: add ...
283
  		set_nlink(inode, de->nlink);
2b579beec   Miklos Szeredi   [PATCH] proc: lin...
284
285
286
287
  
  	generic_fillattr(inode, stat);
  	return 0;
  }
c5ef1c42c   Arjan van de Ven   [PATCH] mark stru...
288
  static const struct inode_operations proc_file_inode_operations = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
289
290
291
292
293
294
295
296
  	.setattr	= proc_notify_change,
  };
  
  /*
   * This function parses a name such as "tty/driver/serial", and
   * returns the struct proc_dir_entry for "/proc/tty/driver", and
   * returns "serial" in residual.
   */
e17a5765f   Alexey Dobriyan   proc: do translat...
297
298
  static int __xlate_proc_name(const char *name, struct proc_dir_entry **ret,
  			     const char **residual)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
299
300
301
  {
  	const char     		*cp = name, *next;
  	struct proc_dir_entry	*de;
312ec7e50   Alexey Dobriyan   proc: make struct...
302
  	unsigned int		len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
303

7cee4e00e   Alexey Dobriyan   proc: less specia...
304
305
306
  	de = *ret;
  	if (!de)
  		de = &proc_root;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
307
308
309
310
311
312
313
314
315
316
  	while (1) {
  		next = strchr(cp, '/');
  		if (!next)
  			break;
  
  		len = next - cp;
  		for (de = de->subdir; de ; de = de->next) {
  			if (proc_match(len, cp, de))
  				break;
  		}
12bac0d9f   Alexey Dobriyan   proc: warn on non...
317
318
319
  		if (!de) {
  			WARN(1, "name '%s'
  ", name);
e17a5765f   Alexey Dobriyan   proc: do translat...
320
  			return -ENOENT;
12bac0d9f   Alexey Dobriyan   proc: warn on non...
321
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
322
323
324
325
  		cp += len + 1;
  	}
  	*residual = cp;
  	*ret = de;
e17a5765f   Alexey Dobriyan   proc: do translat...
326
327
328
329
330
331
332
333
334
335
  	return 0;
  }
  
  static int xlate_proc_name(const char *name, struct proc_dir_entry **ret,
  			   const char **residual)
  {
  	int rv;
  
  	spin_lock(&proc_subdir_lock);
  	rv = __xlate_proc_name(name, ret, residual);
64a07bd82   Steven Rostedt   [PATCH] protect r...
336
  	spin_unlock(&proc_subdir_lock);
e17a5765f   Alexey Dobriyan   proc: do translat...
337
  	return rv;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
338
  }
9a1854091   Alexey Dobriyan   [PATCH 2/2] proc:...
339
  static DEFINE_IDA(proc_inum_ida);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
340
  static DEFINE_SPINLOCK(proc_inum_lock); /* protects the above */
67935df49   Alexey Dobriyan   [PATCH 1/2] proc:...
341
  #define PROC_DYNAMIC_FIRST 0xF0000000U
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
342
343
344
345
346
347
348
  
  /*
   * Return an inode number between PROC_DYNAMIC_FIRST and
   * 0xffffffff, or zero on failure.
   */
  static unsigned int get_inode_number(void)
  {
67935df49   Alexey Dobriyan   [PATCH 1/2] proc:...
349
  	unsigned int i;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
350
351
352
  	int error;
  
  retry:
9a1854091   Alexey Dobriyan   [PATCH 2/2] proc:...
353
  	if (ida_pre_get(&proc_inum_ida, GFP_KERNEL) == 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
354
355
356
  		return 0;
  
  	spin_lock(&proc_inum_lock);
9a1854091   Alexey Dobriyan   [PATCH 2/2] proc:...
357
  	error = ida_get_new(&proc_inum_ida, &i);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
358
359
360
361
362
  	spin_unlock(&proc_inum_lock);
  	if (error == -EAGAIN)
  		goto retry;
  	else if (error)
  		return 0;
67935df49   Alexey Dobriyan   [PATCH 1/2] proc:...
363
364
  	if (i > UINT_MAX - PROC_DYNAMIC_FIRST) {
  		spin_lock(&proc_inum_lock);
9a1854091   Alexey Dobriyan   [PATCH 2/2] proc:...
365
  		ida_remove(&proc_inum_ida, i);
67935df49   Alexey Dobriyan   [PATCH 1/2] proc:...
366
  		spin_unlock(&proc_inum_lock);
cc9960991   Alexey Dobriyan   [PATCH] proc: ino...
367
  		return 0;
67935df49   Alexey Dobriyan   [PATCH 1/2] proc:...
368
369
  	}
  	return PROC_DYNAMIC_FIRST + i;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
370
371
372
373
  }
  
  static void release_inode_number(unsigned int inum)
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
374
  	spin_lock(&proc_inum_lock);
9a1854091   Alexey Dobriyan   [PATCH 2/2] proc:...
375
  	ida_remove(&proc_inum_ida, inum - PROC_DYNAMIC_FIRST);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
376
377
  	spin_unlock(&proc_inum_lock);
  }
008b150a3   Al Viro   [PATCH] Fix up sy...
378
  static void *proc_follow_link(struct dentry *dentry, struct nameidata *nd)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
379
380
  {
  	nd_set_link(nd, PDE(dentry->d_inode)->data);
008b150a3   Al Viro   [PATCH] Fix up sy...
381
  	return NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
382
  }
c5ef1c42c   Arjan van de Ven   [PATCH] mark stru...
383
  static const struct inode_operations proc_link_inode_operations = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
384
385
386
387
388
389
390
391
392
393
  	.readlink	= generic_readlink,
  	.follow_link	= proc_follow_link,
  };
  
  /*
   * As some entries in /proc are volatile, we want to 
   * get rid of unused dentries.  This could be made 
   * smarter: we could keep a "volatile" flag in the 
   * inode to indicate which ones to keep.
   */
fe15ce446   Nick Piggin   fs: change d_dele...
394
  static int proc_delete_dentry(const struct dentry * dentry)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
395
396
397
  {
  	return 1;
  }
d72f71eb0   Al Viro   constify dentry_o...
398
  static const struct dentry_operations proc_dentry_operations =
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
399
400
401
402
403
404
405
406
  {
  	.d_delete	= proc_delete_dentry,
  };
  
  /*
   * Don't create negative dentries here, return -ENOENT by hand
   * instead.
   */
e9720acd7   Pavel Emelyanov   [NET]: Make /proc...
407
408
  struct dentry *proc_lookup_de(struct proc_dir_entry *de, struct inode *dir,
  		struct dentry *dentry)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
409
410
  {
  	struct inode *inode = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
411
  	int error = -ENOENT;
64a07bd82   Steven Rostedt   [PATCH] protect r...
412
  	spin_lock(&proc_subdir_lock);
5e971dce0   Alexey Dobriyan   proc: drop severa...
413
414
415
416
  	for (de = de->subdir; de ; de = de->next) {
  		if (de->namelen != dentry->d_name.len)
  			continue;
  		if (!memcmp(dentry->d_name.name, de->name, de->namelen)) {
135d5655d   Alexey Dobriyan   proc: rename de_g...
417
  			pde_get(de);
5e971dce0   Alexey Dobriyan   proc: drop severa...
418
419
  			spin_unlock(&proc_subdir_lock);
  			error = -EINVAL;
6d1b6e4ef   Alexey Dobriyan   proc: ->low_ino c...
420
  			inode = proc_get_inode(dir->i_sb, de);
5e971dce0   Alexey Dobriyan   proc: drop severa...
421
  			goto out_unlock;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
422
423
  		}
  	}
64a07bd82   Steven Rostedt   [PATCH] protect r...
424
  	spin_unlock(&proc_subdir_lock);
4237e0d3d   Alexey Dobriyan   proc: less LOCK o...
425
  out_unlock:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
426
427
  
  	if (inode) {
fb045adb9   Nick Piggin   fs: dcache reduce...
428
  		d_set_d_op(dentry, &proc_dentry_operations);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
429
430
431
  		d_add(dentry, inode);
  		return NULL;
  	}
5e971dce0   Alexey Dobriyan   proc: drop severa...
432
  	if (de)
135d5655d   Alexey Dobriyan   proc: rename de_g...
433
  		pde_put(de);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
434
435
  	return ERR_PTR(error);
  }
e9720acd7   Pavel Emelyanov   [NET]: Make /proc...
436
437
438
439
440
  struct dentry *proc_lookup(struct inode *dir, struct dentry *dentry,
  		struct nameidata *nd)
  {
  	return proc_lookup_de(PDE(dir), dir, dentry);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
441
442
443
444
445
446
447
448
449
  /*
   * This returns non-zero if at EOF, so that the /proc
   * root directory can use this and check if it should
   * continue with the <pid> entries..
   *
   * Note that the VFS-layer doesn't care about the return
   * value of the readdir() call, as long as it's non-negative
   * for success..
   */
e9720acd7   Pavel Emelyanov   [NET]: Make /proc...
450
451
  int proc_readdir_de(struct proc_dir_entry *de, struct file *filp, void *dirent,
  		filldir_t filldir)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
452
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
453
454
  	unsigned int ino;
  	int i;
2fddfeefe   Josef "Jeff" Sipek   [PATCH] proc: cha...
455
  	struct inode *inode = filp->f_path.dentry->d_inode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
456
  	int ret = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
457
  	ino = inode->i_ino;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
458
459
460
461
462
463
464
465
466
467
  	i = filp->f_pos;
  	switch (i) {
  		case 0:
  			if (filldir(dirent, ".", 1, i, ino, DT_DIR) < 0)
  				goto out;
  			i++;
  			filp->f_pos++;
  			/* fall through */
  		case 1:
  			if (filldir(dirent, "..", 2, i,
2fddfeefe   Josef "Jeff" Sipek   [PATCH] proc: cha...
468
  				    parent_ino(filp->f_path.dentry),
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
469
470
471
472
473
474
  				    DT_DIR) < 0)
  				goto out;
  			i++;
  			filp->f_pos++;
  			/* fall through */
  		default:
64a07bd82   Steven Rostedt   [PATCH] protect r...
475
  			spin_lock(&proc_subdir_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
476
477
478
479
480
  			de = de->subdir;
  			i -= 2;
  			for (;;) {
  				if (!de) {
  					ret = 1;
64a07bd82   Steven Rostedt   [PATCH] protect r...
481
  					spin_unlock(&proc_subdir_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
482
483
484
485
486
487
488
489
490
  					goto out;
  				}
  				if (!i)
  					break;
  				de = de->next;
  				i--;
  			}
  
  			do {
59cd0cbc7   Darrick J. Wong   Fix race between ...
491
  				struct proc_dir_entry *next;
64a07bd82   Steven Rostedt   [PATCH] protect r...
492
  				/* filldir passes info to user space */
135d5655d   Alexey Dobriyan   proc: rename de_g...
493
  				pde_get(de);
64a07bd82   Steven Rostedt   [PATCH] protect r...
494
  				spin_unlock(&proc_subdir_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
495
  				if (filldir(dirent, de->name, de->namelen, filp->f_pos,
59cd0cbc7   Darrick J. Wong   Fix race between ...
496
  					    de->low_ino, de->mode >> 12) < 0) {
135d5655d   Alexey Dobriyan   proc: rename de_g...
497
  					pde_put(de);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
498
  					goto out;
59cd0cbc7   Darrick J. Wong   Fix race between ...
499
  				}
64a07bd82   Steven Rostedt   [PATCH] protect r...
500
  				spin_lock(&proc_subdir_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
501
  				filp->f_pos++;
59cd0cbc7   Darrick J. Wong   Fix race between ...
502
  				next = de->next;
135d5655d   Alexey Dobriyan   proc: rename de_g...
503
  				pde_put(de);
59cd0cbc7   Darrick J. Wong   Fix race between ...
504
  				de = next;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
505
  			} while (de);
64a07bd82   Steven Rostedt   [PATCH] protect r...
506
  			spin_unlock(&proc_subdir_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
507
508
  	}
  	ret = 1;
b4df2b92d   Alexey Dobriyan   proc: stop using BKL
509
  out:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
510
511
  	return ret;	
  }
e9720acd7   Pavel Emelyanov   [NET]: Make /proc...
512
513
514
515
516
517
  int proc_readdir(struct file *filp, void *dirent, filldir_t filldir)
  {
  	struct inode *inode = filp->f_path.dentry->d_inode;
  
  	return proc_readdir_de(PDE(inode), filp, dirent, filldir);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
518
519
520
521
522
  /*
   * These are the generic /proc directory operations. They
   * use the in-memory "struct proc_dir_entry" tree to parse
   * the /proc directory.
   */
00977a59b   Arjan van de Ven   [PATCH] mark stru...
523
  static const struct file_operations proc_dir_operations = {
b4df2b92d   Alexey Dobriyan   proc: stop using BKL
524
  	.llseek			= generic_file_llseek,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
525
526
527
528
529
530
531
  	.read			= generic_read_dir,
  	.readdir		= proc_readdir,
  };
  
  /*
   * proc directories can do almost nothing..
   */
c5ef1c42c   Arjan van de Ven   [PATCH] mark stru...
532
  static const struct inode_operations proc_dir_inode_operations = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
533
  	.lookup		= proc_lookup,
2b579beec   Miklos Szeredi   [PATCH] proc: lin...
534
  	.getattr	= proc_getattr,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
535
536
537
538
539
540
  	.setattr	= proc_notify_change,
  };
  
  static int proc_register(struct proc_dir_entry * dir, struct proc_dir_entry * dp)
  {
  	unsigned int i;
94413d880   Zhang Rui   proc: detect dupl...
541
  	struct proc_dir_entry *tmp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
542
543
544
545
546
  	
  	i = get_inode_number();
  	if (i == 0)
  		return -EAGAIN;
  	dp->low_ino = i;
64a07bd82   Steven Rostedt   [PATCH] protect r...
547

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
  	if (S_ISDIR(dp->mode)) {
  		if (dp->proc_iops == NULL) {
  			dp->proc_fops = &proc_dir_operations;
  			dp->proc_iops = &proc_dir_inode_operations;
  		}
  		dir->nlink++;
  	} else if (S_ISLNK(dp->mode)) {
  		if (dp->proc_iops == NULL)
  			dp->proc_iops = &proc_link_inode_operations;
  	} else if (S_ISREG(dp->mode)) {
  		if (dp->proc_fops == NULL)
  			dp->proc_fops = &proc_file_operations;
  		if (dp->proc_iops == NULL)
  			dp->proc_iops = &proc_file_inode_operations;
  	}
99fc06df7   Changli Gao   procfs directory ...
563
564
  
  	spin_lock(&proc_subdir_lock);
94413d880   Zhang Rui   proc: detect dupl...
565
566
567
  
  	for (tmp = dir->subdir; tmp; tmp = tmp->next)
  		if (strcmp(tmp->name, dp->name) == 0) {
6c2f91e07   Arjan van de Ven   proc: use WARN() ...
568
569
  			WARN(1, KERN_WARNING "proc_dir_entry '%s/%s' already registered
  ",
665020c35   Alexey Dobriyan   proc: more debugg...
570
  				dir->name, dp->name);
94413d880   Zhang Rui   proc: detect dupl...
571
572
  			break;
  		}
99fc06df7   Changli Gao   procfs directory ...
573
574
575
576
  	dp->next = dir->subdir;
  	dp->parent = dir;
  	dir->subdir = dp;
  	spin_unlock(&proc_subdir_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
577
578
  	return 0;
  }
2d3a4e366   Alexey Dobriyan   proc: fix ->open'...
579
  static struct proc_dir_entry *__proc_create(struct proc_dir_entry **parent,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
580
581
582
583
584
585
  					  const char *name,
  					  mode_t mode,
  					  nlink_t nlink)
  {
  	struct proc_dir_entry *ent = NULL;
  	const char *fn = name;
312ec7e50   Alexey Dobriyan   proc: make struct...
586
  	unsigned int len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
587
588
589
  
  	/* make sure name is valid */
  	if (!name || !strlen(name)) goto out;
7cee4e00e   Alexey Dobriyan   proc: less specia...
590
  	if (xlate_proc_name(name, parent, &fn) != 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
591
592
593
594
595
596
597
598
599
600
601
602
  		goto out;
  
  	/* At this point there must not be any '/' characters beyond *fn */
  	if (strchr(fn, '/'))
  		goto out;
  
  	len = strlen(fn);
  
  	ent = kmalloc(sizeof(struct proc_dir_entry) + len + 1, GFP_KERNEL);
  	if (!ent) goto out;
  
  	memset(ent, 0, sizeof(struct proc_dir_entry));
09570f914   David Howells   proc: make struct...
603
  	memcpy(ent->name, fn, len + 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
604
605
606
  	ent->namelen = len;
  	ent->mode = mode;
  	ent->nlink = nlink;
5a622f2d0   Alexey Dobriyan   proc: fix proc_di...
607
  	atomic_set(&ent->count, 1);
786d7e161   Alexey Dobriyan   Fix rmmod/read/wr...
608
609
610
  	ent->pde_users = 0;
  	spin_lock_init(&ent->pde_unload_lock);
  	ent->pde_unload_completion = NULL;
881adb853   Alexey Dobriyan   proc: always do -...
611
  	INIT_LIST_HEAD(&ent->pde_openers);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
612
613
614
615
616
617
618
619
   out:
  	return ent;
  }
  
  struct proc_dir_entry *proc_symlink(const char *name,
  		struct proc_dir_entry *parent, const char *dest)
  {
  	struct proc_dir_entry *ent;
2d3a4e366   Alexey Dobriyan   proc: fix ->open'...
620
  	ent = __proc_create(&parent, name,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
  			  (S_IFLNK | S_IRUGO | S_IWUGO | S_IXUGO),1);
  
  	if (ent) {
  		ent->data = kmalloc((ent->size=strlen(dest))+1, GFP_KERNEL);
  		if (ent->data) {
  			strcpy((char*)ent->data,dest);
  			if (proc_register(parent, ent) < 0) {
  				kfree(ent->data);
  				kfree(ent);
  				ent = NULL;
  			}
  		} else {
  			kfree(ent);
  			ent = NULL;
  		}
  	}
  	return ent;
  }
587d4a17d   Helight.Xu   some clean up in ...
639
  EXPORT_SYMBOL(proc_symlink);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
640
641
642
643
644
  
  struct proc_dir_entry *proc_mkdir_mode(const char *name, mode_t mode,
  		struct proc_dir_entry *parent)
  {
  	struct proc_dir_entry *ent;
2d3a4e366   Alexey Dobriyan   proc: fix ->open'...
645
  	ent = __proc_create(&parent, name, S_IFDIR | mode, 2);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
646
  	if (ent) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
647
648
649
650
651
652
653
  		if (proc_register(parent, ent) < 0) {
  			kfree(ent);
  			ent = NULL;
  		}
  	}
  	return ent;
  }
011159a0a   Alexey Dobriyan   airo: correct pro...
654
  EXPORT_SYMBOL(proc_mkdir_mode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
655

78e92b99e   Denis V. Lunev   netns: assign PDE...
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
  struct proc_dir_entry *proc_net_mkdir(struct net *net, const char *name,
  		struct proc_dir_entry *parent)
  {
  	struct proc_dir_entry *ent;
  
  	ent = __proc_create(&parent, name, S_IFDIR | S_IRUGO | S_IXUGO, 2);
  	if (ent) {
  		ent->data = net;
  		if (proc_register(parent, ent) < 0) {
  			kfree(ent);
  			ent = NULL;
  		}
  	}
  	return ent;
  }
  EXPORT_SYMBOL_GPL(proc_net_mkdir);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
672
673
674
675
676
  struct proc_dir_entry *proc_mkdir(const char *name,
  		struct proc_dir_entry *parent)
  {
  	return proc_mkdir_mode(name, S_IRUGO | S_IXUGO, parent);
  }
587d4a17d   Helight.Xu   some clean up in ...
677
  EXPORT_SYMBOL(proc_mkdir);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
  
  struct proc_dir_entry *create_proc_entry(const char *name, mode_t mode,
  					 struct proc_dir_entry *parent)
  {
  	struct proc_dir_entry *ent;
  	nlink_t nlink;
  
  	if (S_ISDIR(mode)) {
  		if ((mode & S_IALLUGO) == 0)
  			mode |= S_IRUGO | S_IXUGO;
  		nlink = 2;
  	} else {
  		if ((mode & S_IFMT) == 0)
  			mode |= S_IFREG;
  		if ((mode & S_IALLUGO) == 0)
  			mode |= S_IRUGO;
  		nlink = 1;
  	}
2d3a4e366   Alexey Dobriyan   proc: fix ->open'...
696
  	ent = __proc_create(&parent, name, mode, nlink);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
697
  	if (ent) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
698
699
700
701
702
703
704
  		if (proc_register(parent, ent) < 0) {
  			kfree(ent);
  			ent = NULL;
  		}
  	}
  	return ent;
  }
587d4a17d   Helight.Xu   some clean up in ...
705
  EXPORT_SYMBOL(create_proc_entry);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
706

59b743514   Denis V. Lunev   proc: introduce p...
707
708
709
710
  struct proc_dir_entry *proc_create_data(const char *name, mode_t mode,
  					struct proc_dir_entry *parent,
  					const struct file_operations *proc_fops,
  					void *data)
2d3a4e366   Alexey Dobriyan   proc: fix ->open'...
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
  {
  	struct proc_dir_entry *pde;
  	nlink_t nlink;
  
  	if (S_ISDIR(mode)) {
  		if ((mode & S_IALLUGO) == 0)
  			mode |= S_IRUGO | S_IXUGO;
  		nlink = 2;
  	} else {
  		if ((mode & S_IFMT) == 0)
  			mode |= S_IFREG;
  		if ((mode & S_IALLUGO) == 0)
  			mode |= S_IRUGO;
  		nlink = 1;
  	}
  
  	pde = __proc_create(&parent, name, mode, nlink);
  	if (!pde)
  		goto out;
  	pde->proc_fops = proc_fops;
59b743514   Denis V. Lunev   proc: introduce p...
731
  	pde->data = data;
2d3a4e366   Alexey Dobriyan   proc: fix ->open'...
732
733
734
735
736
737
738
739
  	if (proc_register(parent, pde) < 0)
  		goto out_free;
  	return pde;
  out_free:
  	kfree(pde);
  out:
  	return NULL;
  }
587d4a17d   Helight.Xu   some clean up in ...
740
  EXPORT_SYMBOL(proc_create_data);
2d3a4e366   Alexey Dobriyan   proc: fix ->open'...
741

135d5655d   Alexey Dobriyan   proc: rename de_g...
742
  static void free_proc_entry(struct proc_dir_entry *de)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
743
  {
6d1b6e4ef   Alexey Dobriyan   proc: ->low_ino c...
744
  	release_inode_number(de->low_ino);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
745

fd2cbe488   Alexey Dobriyan   proc: remove usel...
746
  	if (S_ISLNK(de->mode))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
747
748
749
  		kfree(de->data);
  	kfree(de);
  }
135d5655d   Alexey Dobriyan   proc: rename de_g...
750
751
752
753
754
  void pde_put(struct proc_dir_entry *pde)
  {
  	if (atomic_dec_and_test(&pde->count))
  		free_proc_entry(pde);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
755
756
  /*
   * Remove a /proc entry and free it if it's not currently in use.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
757
758
759
760
   */
  void remove_proc_entry(const char *name, struct proc_dir_entry *parent)
  {
  	struct proc_dir_entry **p;
f649d6d32   Alexey Dobriyan   proc: simplify lo...
761
  	struct proc_dir_entry *de = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
762
  	const char *fn = name;
312ec7e50   Alexey Dobriyan   proc: make struct...
763
  	unsigned int len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
764

e17a5765f   Alexey Dobriyan   proc: do translat...
765
766
767
  	spin_lock(&proc_subdir_lock);
  	if (__xlate_proc_name(name, &parent, &fn) != 0) {
  		spin_unlock(&proc_subdir_lock);
f649d6d32   Alexey Dobriyan   proc: simplify lo...
768
  		return;
e17a5765f   Alexey Dobriyan   proc: do translat...
769
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
770
  	len = strlen(fn);
64a07bd82   Steven Rostedt   [PATCH] protect r...
771

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
772
  	for (p = &parent->subdir; *p; p=&(*p)->next ) {
f649d6d32   Alexey Dobriyan   proc: simplify lo...
773
774
775
776
777
778
779
780
  		if (proc_match(len, fn, *p)) {
  			de = *p;
  			*p = de->next;
  			de->next = NULL;
  			break;
  		}
  	}
  	spin_unlock(&proc_subdir_lock);
12bac0d9f   Alexey Dobriyan   proc: warn on non...
781
782
783
  	if (!de) {
  		WARN(1, "name '%s'
  ", name);
f649d6d32   Alexey Dobriyan   proc: simplify lo...
784
  		return;
12bac0d9f   Alexey Dobriyan   proc: warn on non...
785
  	}
786d7e161   Alexey Dobriyan   Fix rmmod/read/wr...
786

f649d6d32   Alexey Dobriyan   proc: simplify lo...
787
788
789
790
791
792
793
794
795
796
797
798
  	spin_lock(&de->pde_unload_lock);
  	/*
  	 * Stop accepting new callers into module. If you're
  	 * dynamically allocating ->proc_fops, save a pointer somewhere.
  	 */
  	de->proc_fops = NULL;
  	/* Wait until all existing callers into module are done. */
  	if (de->pde_users > 0) {
  		DECLARE_COMPLETION_ONSTACK(c);
  
  		if (!de->pde_unload_completion)
  			de->pde_unload_completion = &c;
786d7e161   Alexey Dobriyan   Fix rmmod/read/wr...
799

786d7e161   Alexey Dobriyan   Fix rmmod/read/wr...
800
  		spin_unlock(&de->pde_unload_lock);
f649d6d32   Alexey Dobriyan   proc: simplify lo...
801
  		wait_for_completion(de->pde_unload_completion);
3740a20c4   Alexey Dobriyan   proc: less LOCK/U...
802
  		spin_lock(&de->pde_unload_lock);
f649d6d32   Alexey Dobriyan   proc: simplify lo...
803
  	}
f649d6d32   Alexey Dobriyan   proc: simplify lo...
804

881adb853   Alexey Dobriyan   proc: always do -...
805
806
807
808
809
810
811
812
813
814
815
  	while (!list_empty(&de->pde_openers)) {
  		struct pde_opener *pdeo;
  
  		pdeo = list_first_entry(&de->pde_openers, struct pde_opener, lh);
  		list_del(&pdeo->lh);
  		spin_unlock(&de->pde_unload_lock);
  		pdeo->release(pdeo->inode, pdeo->file);
  		kfree(pdeo);
  		spin_lock(&de->pde_unload_lock);
  	}
  	spin_unlock(&de->pde_unload_lock);
f649d6d32   Alexey Dobriyan   proc: simplify lo...
816
817
818
  	if (S_ISDIR(de->mode))
  		parent->nlink--;
  	de->nlink = 0;
267e2a9c7   Arjan van de Ven   Use WARN() in fs/...
819
  	WARN(de->subdir, KERN_WARNING "%s: removing non-empty directory "
f649d6d32   Alexey Dobriyan   proc: simplify lo...
820
821
822
  			"'%s/%s', leaking at least '%s'
  ", __func__,
  			de->parent->name, de->name, de->subdir->name);
135d5655d   Alexey Dobriyan   proc: rename de_g...
823
  	pde_put(de);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
824
  }
587d4a17d   Helight.Xu   some clean up in ...
825
  EXPORT_SYMBOL(remove_proc_entry);