aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNeil Horman <nhorman@redhat.com>2006-01-14 16:20:38 -0500
committerLinus Torvalds <torvalds@g5.osdl.org>2006-01-14 21:25:19 -0500
commit7170be5f586b59bdcdab082778a5d9203ba7b667 (patch)
tree00d34a062c5bbab83315232078296567037bd3f4
parentfaf3a98918aa5f14a29e0d246e194be58b9357f0 (diff)
[PATCH] convert /proc/devices to use seq_file interface
A Christoph suggested that the /proc/devices file be converted to use the seq_file interface. This patch does that. I've obxerved one or two installation that had sufficiently large sans that they overran the 4k limit on /proc/devices. Signed-off-by: Neil Horman <nhorman@redhat.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r--block/genhd.c106
-rw-r--r--fs/char_dev.c96
-rw-r--r--fs/proc/proc_misc.c160
-rw-r--r--include/linux/fs.h11
4 files changed, 320 insertions, 53 deletions
diff --git a/block/genhd.c b/block/genhd.c
index f1ed83f3f083..db57546a709d 100644
--- a/block/genhd.c
+++ b/block/genhd.c
@@ -38,34 +38,100 @@ static inline int major_to_index(int major)
38 return major % MAX_PROBE_HASH; 38 return major % MAX_PROBE_HASH;
39} 39}
40 40
41#ifdef CONFIG_PROC_FS 41struct blkdev_info {
42/* get block device names in somewhat random order */ 42 int index;
43int get_blkdev_list(char *p, int used) 43 struct blk_major_name *bd;
44};
45
46/*
47 * iterate over a list of blkdev_info structures. allows
48 * the major_names array to be iterated over from outside this file
49 * must be called with the block_subsys_sem held
50 */
51void *get_next_blkdev(void *dev)
52{
53 struct blkdev_info *info;
54
55 if (dev == NULL) {
56 info = kmalloc(sizeof(*info), GFP_KERNEL);
57 if (!info)
58 goto out;
59 info->index=0;
60 info->bd = major_names[info->index];
61 if (info->bd)
62 goto out;
63 } else {
64 info = dev;
65 }
66
67 while (info->index < ARRAY_SIZE(major_names)) {
68 if (info->bd)
69 info->bd = info->bd->next;
70 if (info->bd)
71 goto out;
72 /*
73 * No devices on this chain, move to the next
74 */
75 info->index++;
76 info->bd = (info->index < ARRAY_SIZE(major_names)) ?
77 major_names[info->index] : NULL;
78 if (info->bd)
79 goto out;
80 }
81
82out:
83 return info;
84}
85
86void *acquire_blkdev_list(void)
87{
88 down(&block_subsys_sem);
89 return get_next_blkdev(NULL);
90}
91
92void release_blkdev_list(void *dev)
93{
94 up(&block_subsys_sem);
95 kfree(dev);
96}
97
98
99/*
100 * Count the number of records in the blkdev_list.
101 * must be called with the block_subsys_sem held
102 */
103int count_blkdev_list(void)
44{ 104{
45 struct blk_major_name *n; 105 struct blk_major_name *n;
46 int i, len; 106 int i, count;
47 107
48 len = snprintf(p, (PAGE_SIZE-used), "\nBlock devices:\n"); 108 count = 0;
49 109
50 down(&block_subsys_sem);
51 for (i = 0; i < ARRAY_SIZE(major_names); i++) { 110 for (i = 0; i < ARRAY_SIZE(major_names); i++) {
52 for (n = major_names[i]; n; n = n->next) { 111 for (n = major_names[i]; n; n = n->next)
53 /* 112 count++;
54 * If the curent string plus the 5 extra characters
55 * in the line would run us off the page, then we're done
56 */
57 if ((len + used + strlen(n->name) + 5) >= PAGE_SIZE)
58 goto page_full;
59 len += sprintf(p+len, "%3d %s\n",
60 n->major, n->name);
61 }
62 } 113 }
63page_full:
64 up(&block_subsys_sem);
65 114
66 return len; 115 return count;
67} 116}
68#endif 117
118/*
119 * extract the major and name values from a blkdev_info struct
120 * passed in as a void to *dev. Must be called with
121 * block_subsys_sem held
122 */
123int get_blkdev_info(void *dev, int *major, char **name)
124{
125 struct blkdev_info *info = dev;
126
127 if (info->bd == NULL)
128 return 1;
129
130 *major = info->bd->major;
131 *name = info->bd->name;
132 return 0;
133}
134
69 135
70int register_blkdev(unsigned int major, const char *name) 136int register_blkdev(unsigned int major, const char *name)
71{ 137{
diff --git a/fs/char_dev.c b/fs/char_dev.c
index 3b1b1eefdbb0..21195c481637 100644
--- a/fs/char_dev.c
+++ b/fs/char_dev.c
@@ -35,7 +35,7 @@ static struct char_device_struct {
35 unsigned int major; 35 unsigned int major;
36 unsigned int baseminor; 36 unsigned int baseminor;
37 int minorct; 37 int minorct;
38 const char *name; 38 char name[64];
39 struct file_operations *fops; 39 struct file_operations *fops;
40 struct cdev *cdev; /* will die */ 40 struct cdev *cdev; /* will die */
41} *chrdevs[MAX_PROBE_HASH]; 41} *chrdevs[MAX_PROBE_HASH];
@@ -46,34 +46,84 @@ static inline int major_to_index(int major)
46 return major % MAX_PROBE_HASH; 46 return major % MAX_PROBE_HASH;
47} 47}
48 48
49/* get char device names in somewhat random order */ 49struct chrdev_info {
50int get_chrdev_list(char *page) 50 int index;
51{
52 struct char_device_struct *cd; 51 struct char_device_struct *cd;
53 int i, len; 52};
54 53
55 len = sprintf(page, "Character devices:\n"); 54void *get_next_chrdev(void *dev)
55{
56 struct chrdev_info *info;
56 57
58 if (dev == NULL) {
59 info = kmalloc(sizeof(*info), GFP_KERNEL);
60 if (!info)
61 goto out;
62 info->index=0;
63 info->cd = chrdevs[info->index];
64 if (info->cd)
65 goto out;
66 } else {
67 info = dev;
68 }
69
70 while (info->index < ARRAY_SIZE(chrdevs)) {
71 if (info->cd)
72 info->cd = info->cd->next;
73 if (info->cd)
74 goto out;
75 /*
76 * No devices on this chain, move to the next
77 */
78 info->index++;
79 info->cd = (info->index < ARRAY_SIZE(chrdevs)) ?
80 chrdevs[info->index] : NULL;
81 if (info->cd)
82 goto out;
83 }
84
85out:
86 return info;
87}
88
89void *acquire_chrdev_list(void)
90{
57 down(&chrdevs_lock); 91 down(&chrdevs_lock);
92 return get_next_chrdev(NULL);
93}
94
95void release_chrdev_list(void *dev)
96{
97 up(&chrdevs_lock);
98 kfree(dev);
99}
100
101
102int count_chrdev_list(void)
103{
104 struct char_device_struct *cd;
105 int i, count;
106
107 count = 0;
108
58 for (i = 0; i < ARRAY_SIZE(chrdevs) ; i++) { 109 for (i = 0; i < ARRAY_SIZE(chrdevs) ; i++) {
59 for (cd = chrdevs[i]; cd; cd = cd->next) { 110 for (cd = chrdevs[i]; cd; cd = cd->next)
60 /* 111 count++;
61 * if the current name, plus the 5 extra characters
62 * in the device line for this entry
63 * would run us off the page, we're done
64 */
65 if ((len+strlen(cd->name) + 5) >= PAGE_SIZE)
66 goto page_full;
67
68
69 len += sprintf(page+len, "%3d %s\n",
70 cd->major, cd->name);
71 }
72 } 112 }
73page_full:
74 up(&chrdevs_lock);
75 113
76 return len; 114 return count;
115}
116
117int get_chrdev_info(void *dev, int *major, char **name)
118{
119 struct chrdev_info *info = dev;
120
121 if (info->cd == NULL)
122 return 1;
123
124 *major = info->cd->major;
125 *name = info->cd->name;
126 return 0;
77} 127}
78 128
79/* 129/*
@@ -121,7 +171,7 @@ __register_chrdev_region(unsigned int major, unsigned int baseminor,
121 cd->major = major; 171 cd->major = major;
122 cd->baseminor = baseminor; 172 cd->baseminor = baseminor;
123 cd->minorct = minorct; 173 cd->minorct = minorct;
124 cd->name = name; 174 strncpy(cd->name,name, 64);
125 175
126 i = major_to_index(major); 176 i = major_to_index(major);
127 177
diff --git a/fs/proc/proc_misc.c b/fs/proc/proc_misc.c
index 63bf6c00fa0c..8f8014285a34 100644
--- a/fs/proc/proc_misc.c
+++ b/fs/proc/proc_misc.c
@@ -20,6 +20,7 @@
20#include <linux/time.h> 20#include <linux/time.h>
21#include <linux/kernel.h> 21#include <linux/kernel.h>
22#include <linux/kernel_stat.h> 22#include <linux/kernel_stat.h>
23#include <linux/fs.h>
23#include <linux/tty.h> 24#include <linux/tty.h>
24#include <linux/string.h> 25#include <linux/string.h>
25#include <linux/mman.h> 26#include <linux/mman.h>
@@ -62,7 +63,6 @@
62 */ 63 */
63extern int get_hardware_list(char *); 64extern int get_hardware_list(char *);
64extern int get_stram_list(char *); 65extern int get_stram_list(char *);
65extern int get_chrdev_list(char *);
66extern int get_filesystem_list(char *); 66extern int get_filesystem_list(char *);
67extern int get_exec_domain_list(char *); 67extern int get_exec_domain_list(char *);
68extern int get_dma_list(char *); 68extern int get_dma_list(char *);
@@ -248,6 +248,154 @@ static int cpuinfo_open(struct inode *inode, struct file *file)
248{ 248{
249 return seq_open(file, &cpuinfo_op); 249 return seq_open(file, &cpuinfo_op);
250} 250}
251
252enum devinfo_states {
253 CHR_HDR,
254 CHR_LIST,
255 BLK_HDR,
256 BLK_LIST,
257 DEVINFO_DONE
258};
259
260struct devinfo_state {
261 void *chrdev;
262 void *blkdev;
263 unsigned int num_records;
264 unsigned int cur_record;
265 enum devinfo_states state;
266};
267
268static void *devinfo_start(struct seq_file *f, loff_t *pos)
269{
270 struct devinfo_state *info = f->private;
271
272 if (*pos) {
273 if ((info) && (*pos <= info->num_records))
274 return info;
275 return NULL;
276 }
277 info = kmalloc(sizeof(*info), GFP_KERNEL);
278 f->private = info;
279 info->chrdev = acquire_chrdev_list();
280 info->blkdev = acquire_blkdev_list();
281 info->state = CHR_HDR;
282 info->num_records = count_chrdev_list();
283 info->num_records += count_blkdev_list();
284 info->num_records += 2; /* Character and Block headers */
285 *pos = 1;
286 info->cur_record = *pos;
287 return info;
288}
289
290static void *devinfo_next(struct seq_file *f, void *v, loff_t *pos)
291{
292 int idummy;
293 char *ndummy;
294 struct devinfo_state *info = f->private;
295
296 switch (info->state) {
297 case CHR_HDR:
298 info->state = CHR_LIST;
299 (*pos)++;
300 /*fallthrough*/
301 case CHR_LIST:
302 if (get_chrdev_info(info->chrdev,&idummy,&ndummy)) {
303 /*
304 * The character dev list is complete
305 */
306 info->state = BLK_HDR;
307 } else {
308 info->chrdev = get_next_chrdev(info->chrdev);
309 }
310 (*pos)++;
311 break;
312 case BLK_HDR:
313 info->state = BLK_LIST;
314 (*pos)++;
315 break;
316 case BLK_LIST:
317 if (get_blkdev_info(info->blkdev,&idummy,&ndummy)) {
318 /*
319 * The block dev list is complete
320 */
321 info->state = DEVINFO_DONE;
322 } else {
323 info->blkdev = get_next_blkdev(info->blkdev);
324 }
325 (*pos)++;
326 break;
327 case DEVINFO_DONE:
328 (*pos)++;
329 info->cur_record = *pos;
330 info = NULL;
331 break;
332 default:
333 break;
334 }
335 if (info)
336 info->cur_record = *pos;
337 return info;
338}
339
340static void devinfo_stop(struct seq_file *f, void *v)
341{
342 struct devinfo_state *info = f->private;
343
344 if (info) {
345 release_chrdev_list(info->chrdev);
346 release_blkdev_list(info->blkdev);
347 f->private = NULL;
348 kfree(info);
349 }
350}
351
352static int devinfo_show(struct seq_file *f, void *arg)
353{
354 int major;
355 char *name;
356 struct devinfo_state *info = f->private;
357
358 switch(info->state) {
359 case CHR_HDR:
360 seq_printf(f,"Character devices:\n");
361 /* fallthrough */
362 case CHR_LIST:
363 if (!get_chrdev_info(info->chrdev,&major,&name))
364 seq_printf(f,"%3d %s\n",major,name);
365 break;
366 case BLK_HDR:
367 seq_printf(f,"\nBlock devices:\n");
368 /* fallthrough */
369 case BLK_LIST:
370 if (!get_blkdev_info(info->blkdev,&major,&name))
371 seq_printf(f,"%3d %s\n",major,name);
372 break;
373 default:
374 break;
375 }
376
377 return 0;
378}
379
380static struct seq_operations devinfo_op = {
381 .start = devinfo_start,
382 .next = devinfo_next,
383 .stop = devinfo_stop,
384 .show = devinfo_show,
385};
386
387static int devinfo_open(struct inode *inode, struct file *file)
388{
389 return seq_open(file, &devinfo_op);
390}
391
392static struct file_operations proc_devinfo_operations = {
393 .open = devinfo_open,
394 .read = seq_read,
395 .llseek = seq_lseek,
396 .release = seq_release,
397};
398
251static struct file_operations proc_cpuinfo_operations = { 399static struct file_operations proc_cpuinfo_operations = {
252 .open = cpuinfo_open, 400 .open = cpuinfo_open,
253 .read = seq_read, 401 .read = seq_read,
@@ -450,14 +598,6 @@ static struct file_operations proc_stat_operations = {
450 .release = single_release, 598 .release = single_release,
451}; 599};
452 600
453static int devices_read_proc(char *page, char **start, off_t off,
454 int count, int *eof, void *data)
455{
456 int len = get_chrdev_list(page);
457 len += get_blkdev_list(page+len, len);
458 return proc_calc_metrics(page, start, off, count, eof, len);
459}
460
461/* 601/*
462 * /proc/interrupts 602 * /proc/interrupts
463 */ 603 */
@@ -582,7 +722,6 @@ void __init proc_misc_init(void)
582#ifdef CONFIG_STRAM_PROC 722#ifdef CONFIG_STRAM_PROC
583 {"stram", stram_read_proc}, 723 {"stram", stram_read_proc},
584#endif 724#endif
585 {"devices", devices_read_proc},
586 {"filesystems", filesystems_read_proc}, 725 {"filesystems", filesystems_read_proc},
587 {"cmdline", cmdline_read_proc}, 726 {"cmdline", cmdline_read_proc},
588 {"locks", locks_read_proc}, 727 {"locks", locks_read_proc},
@@ -598,6 +737,7 @@ void __init proc_misc_init(void)
598 entry = create_proc_entry("kmsg", S_IRUSR, &proc_root); 737 entry = create_proc_entry("kmsg", S_IRUSR, &proc_root);
599 if (entry) 738 if (entry)
600 entry->proc_fops = &proc_kmsg_operations; 739 entry->proc_fops = &proc_kmsg_operations;
740 create_seq_entry("devices", 0, &proc_devinfo_operations);
601 create_seq_entry("cpuinfo", 0, &proc_cpuinfo_operations); 741 create_seq_entry("cpuinfo", 0, &proc_cpuinfo_operations);
602 create_seq_entry("partitions", 0, &proc_partitions_operations); 742 create_seq_entry("partitions", 0, &proc_partitions_operations);
603 create_seq_entry("stat", 0, &proc_stat_operations); 743 create_seq_entry("stat", 0, &proc_stat_operations);
diff --git a/include/linux/fs.h b/include/linux/fs.h
index d1e370d25f7b..552cedfa6064 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -1383,6 +1383,12 @@ extern int register_chrdev(unsigned int, const char *,
1383extern int unregister_chrdev(unsigned int, const char *); 1383extern int unregister_chrdev(unsigned int, const char *);
1384extern void unregister_chrdev_region(dev_t, unsigned); 1384extern void unregister_chrdev_region(dev_t, unsigned);
1385extern int chrdev_open(struct inode *, struct file *); 1385extern int chrdev_open(struct inode *, struct file *);
1386extern int get_chrdev_list(char *);
1387extern void *acquire_chrdev_list(void);
1388extern int count_chrdev_list(void);
1389extern void *get_next_chrdev(void *);
1390extern int get_chrdev_info(void *, int *, char **);
1391extern void release_chrdev_list(void *);
1386 1392
1387/* fs/block_dev.c */ 1393/* fs/block_dev.c */
1388#define BDEVNAME_SIZE 32 /* Largest string for a blockdev identifier */ 1394#define BDEVNAME_SIZE 32 /* Largest string for a blockdev identifier */
@@ -1391,6 +1397,11 @@ extern const char *bdevname(struct block_device *bdev, char *buffer);
1391extern struct block_device *lookup_bdev(const char *); 1397extern struct block_device *lookup_bdev(const char *);
1392extern struct block_device *open_bdev_excl(const char *, int, void *); 1398extern struct block_device *open_bdev_excl(const char *, int, void *);
1393extern void close_bdev_excl(struct block_device *); 1399extern void close_bdev_excl(struct block_device *);
1400extern void *acquire_blkdev_list(void);
1401extern int count_blkdev_list(void);
1402extern void *get_next_blkdev(void *);
1403extern int get_blkdev_info(void *, int *, char **);
1404extern void release_blkdev_list(void *);
1394 1405
1395extern void init_special_inode(struct inode *, umode_t, dev_t); 1406extern void init_special_inode(struct inode *, umode_t, dev_t);
1396 1407