Magellan Linux

Annotation of /trunk/kernel26-magellan/patches-2.6.16-r10/0114-2.6.16.12-proc.patch

Parent Directory Parent Directory | Revision Log Revision Log


Revision 70 - (hide annotations) (download)
Thu May 11 19:09:22 2006 UTC (18 years, 1 month ago) by niro
File size: 13636 byte(s)
import

1 niro 70 From: Andrew Morton <akpm@osdl.org>
2     Date: Fri, 21 Apr 2006 08:51:36 +0000 (-0700)
3     Subject: [PATCH] Simplify proc/devices and fix early termination regression
4     X-Git-Url: http://www.kernel.org/git/?p=linux/kernel/git/stable/linux-2.6.16.y.git;a=commitdiff;h=692c0509fd0719406f8f781d9a9f2e19aa6b7c0a
5    
6     [PATCH] Simplify proc/devices and fix early termination regression
7    
8     Repair /proc/devices early-termination regression.
9    
10     2.6.16 broke /proc/devices. An application often gets an
11     EOF before the end of data is reached, if that application
12     uses a series of short read(2)s to access the data. I have
13     used read buffers of varying sizes with varying degrees
14     of unsuccess (larger sizes get further into the data than
15     smaller sizes, following a simple pattern). It appears
16     that the only safe way to get the data is to use a single
17     read buffer larger than all the data in /proc/devices.
18    
19     The following example demonstates the problem:
20    
21     # dd if=/proc/devices bs=1
22     Character devices:
23     1 mem
24     27+0 records in
25     27+0 records out
26    
27     This patch is a backport of the fix recently accepted to
28     Linus's tree:
29    
30     commit 68eef3b4791572ecb70249c7fb145bb3742dd899
31     [PATCH] Simplify proc/devices and fix early termination regression
32    
33     It replaces the complex, state-machine algorithm introduced
34     in 2.6.16 with a simple algorithm, modeled on the implementation
35     of /proc/interrupts.
36    
37     [akpm@osdl.org: cleanups, simplifications]
38    
39     Signed-off-by: Joe Korty <joe.korty@ccur.com>
40     Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
41     ---
42    
43     --- a/block/genhd.c
44     +++ b/block/genhd.c
45     @@ -16,8 +16,6 @@
46     #include <linux/kobj_map.h>
47     #include <linux/buffer_head.h>
48    
49     -#define MAX_PROBE_HASH 255 /* random */
50     -
51     static struct subsystem block_subsys;
52    
53     static DECLARE_MUTEX(block_subsys_sem);
54     @@ -30,108 +28,29 @@ static struct blk_major_name {
55     struct blk_major_name *next;
56     int major;
57     char name[16];
58     -} *major_names[MAX_PROBE_HASH];
59     +} *major_names[BLKDEV_MAJOR_HASH_SIZE];
60    
61     /* index in the above - for now: assume no multimajor ranges */
62     static inline int major_to_index(int major)
63     {
64     - return major % MAX_PROBE_HASH;
65     -}
66     -
67     -struct blkdev_info {
68     - int index;
69     - struct blk_major_name *bd;
70     -};
71     -
72     -/*
73     - * iterate over a list of blkdev_info structures. allows
74     - * the major_names array to be iterated over from outside this file
75     - * must be called with the block_subsys_sem held
76     - */
77     -void *get_next_blkdev(void *dev)
78     -{
79     - struct blkdev_info *info;
80     -
81     - if (dev == NULL) {
82     - info = kmalloc(sizeof(*info), GFP_KERNEL);
83     - if (!info)
84     - goto out;
85     - info->index=0;
86     - info->bd = major_names[info->index];
87     - if (info->bd)
88     - goto out;
89     - } else {
90     - info = dev;
91     - }
92     -
93     - while (info->index < ARRAY_SIZE(major_names)) {
94     - if (info->bd)
95     - info->bd = info->bd->next;
96     - if (info->bd)
97     - goto out;
98     - /*
99     - * No devices on this chain, move to the next
100     - */
101     - info->index++;
102     - info->bd = (info->index < ARRAY_SIZE(major_names)) ?
103     - major_names[info->index] : NULL;
104     - if (info->bd)
105     - goto out;
106     - }
107     -
108     -out:
109     - return info;
110     -}
111     -
112     -void *acquire_blkdev_list(void)
113     -{
114     - down(&block_subsys_sem);
115     - return get_next_blkdev(NULL);
116     -}
117     -
118     -void release_blkdev_list(void *dev)
119     -{
120     - up(&block_subsys_sem);
121     - kfree(dev);
122     + return major % BLKDEV_MAJOR_HASH_SIZE;
123     }
124    
125     +#ifdef CONFIG_PROC_FS
126    
127     -/*
128     - * Count the number of records in the blkdev_list.
129     - * must be called with the block_subsys_sem held
130     - */
131     -int count_blkdev_list(void)
132     +void blkdev_show(struct seq_file *f, off_t offset)
133     {
134     - struct blk_major_name *n;
135     - int i, count;
136     -
137     - count = 0;
138     + struct blk_major_name *dp;
139    
140     - for (i = 0; i < ARRAY_SIZE(major_names); i++) {
141     - for (n = major_names[i]; n; n = n->next)
142     - count++;
143     + if (offset < BLKDEV_MAJOR_HASH_SIZE) {
144     + down(&block_subsys_sem);
145     + for (dp = major_names[offset]; dp; dp = dp->next)
146     + seq_printf(f, "%3d %s\n", dp->major, dp->name);
147     + up(&block_subsys_sem);
148     }
149     -
150     - return count;
151     -}
152     -
153     -/*
154     - * extract the major and name values from a blkdev_info struct
155     - * passed in as a void to *dev. Must be called with
156     - * block_subsys_sem held
157     - */
158     -int get_blkdev_info(void *dev, int *major, char **name)
159     -{
160     - struct blkdev_info *info = dev;
161     -
162     - if (info->bd == NULL)
163     - return 1;
164     -
165     - *major = info->bd->major;
166     - *name = info->bd->name;
167     - return 0;
168     }
169    
170     +#endif /* CONFIG_PROC_FS */
171    
172     int register_blkdev(unsigned int major, const char *name)
173     {
174     --- a/fs/char_dev.c
175     +++ b/fs/char_dev.c
176     @@ -15,6 +15,7 @@
177     #include <linux/module.h>
178     #include <linux/smp_lock.h>
179     #include <linux/devfs_fs_kernel.h>
180     +#include <linux/seq_file.h>
181    
182     #include <linux/kobject.h>
183     #include <linux/kobj_map.h>
184     @@ -26,8 +27,6 @@
185    
186     static struct kobj_map *cdev_map;
187    
188     -#define MAX_PROBE_HASH 255 /* random */
189     -
190     static DECLARE_MUTEX(chrdevs_lock);
191    
192     static struct char_device_struct {
193     @@ -38,93 +37,29 @@ static struct char_device_struct {
194     char name[64];
195     struct file_operations *fops;
196     struct cdev *cdev; /* will die */
197     -} *chrdevs[MAX_PROBE_HASH];
198     +} *chrdevs[CHRDEV_MAJOR_HASH_SIZE];
199    
200     /* index in the above */
201     static inline int major_to_index(int major)
202     {
203     - return major % MAX_PROBE_HASH;
204     -}
205     -
206     -struct chrdev_info {
207     - int index;
208     - struct char_device_struct *cd;
209     -};
210     -
211     -void *get_next_chrdev(void *dev)
212     -{
213     - struct chrdev_info *info;
214     -
215     - if (dev == NULL) {
216     - info = kmalloc(sizeof(*info), GFP_KERNEL);
217     - if (!info)
218     - goto out;
219     - info->index=0;
220     - info->cd = chrdevs[info->index];
221     - if (info->cd)
222     - goto out;
223     - } else {
224     - info = dev;
225     - }
226     -
227     - while (info->index < ARRAY_SIZE(chrdevs)) {
228     - if (info->cd)
229     - info->cd = info->cd->next;
230     - if (info->cd)
231     - goto out;
232     - /*
233     - * No devices on this chain, move to the next
234     - */
235     - info->index++;
236     - info->cd = (info->index < ARRAY_SIZE(chrdevs)) ?
237     - chrdevs[info->index] : NULL;
238     - if (info->cd)
239     - goto out;
240     - }
241     -
242     -out:
243     - return info;
244     -}
245     -
246     -void *acquire_chrdev_list(void)
247     -{
248     - down(&chrdevs_lock);
249     - return get_next_chrdev(NULL);
250     -}
251     -
252     -void release_chrdev_list(void *dev)
253     -{
254     - up(&chrdevs_lock);
255     - kfree(dev);
256     + return major % CHRDEV_MAJOR_HASH_SIZE;
257     }
258    
259     +#ifdef CONFIG_PROC_FS
260    
261     -int count_chrdev_list(void)
262     +void chrdev_show(struct seq_file *f, off_t offset)
263     {
264     struct char_device_struct *cd;
265     - int i, count;
266     -
267     - count = 0;
268    
269     - for (i = 0; i < ARRAY_SIZE(chrdevs) ; i++) {
270     - for (cd = chrdevs[i]; cd; cd = cd->next)
271     - count++;
272     + if (offset < CHRDEV_MAJOR_HASH_SIZE) {
273     + down(&chrdevs_lock);
274     + for (cd = chrdevs[offset]; cd; cd = cd->next)
275     + seq_printf(f, "%3d %s\n", cd->major, cd->name);
276     + up(&chrdevs_lock);
277     }
278     -
279     - return count;
280     }
281    
282     -int get_chrdev_info(void *dev, int *major, char **name)
283     -{
284     - struct chrdev_info *info = dev;
285     -
286     - if (info->cd == NULL)
287     - return 1;
288     -
289     - *major = info->cd->major;
290     - *name = info->cd->name;
291     - return 0;
292     -}
293     +#endif /* CONFIG_PROC_FS */
294    
295     /*
296     * Register a single major with a specified minor range.
297     --- a/fs/proc/proc_misc.c
298     +++ b/fs/proc/proc_misc.c
299     @@ -249,144 +249,60 @@ static int cpuinfo_open(struct inode *in
300     return seq_open(file, &cpuinfo_op);
301     }
302    
303     -enum devinfo_states {
304     - CHR_HDR,
305     - CHR_LIST,
306     - BLK_HDR,
307     - BLK_LIST,
308     - DEVINFO_DONE
309     -};
310     -
311     -struct devinfo_state {
312     - void *chrdev;
313     - void *blkdev;
314     - unsigned int num_records;
315     - unsigned int cur_record;
316     - enum devinfo_states state;
317     +static struct file_operations proc_cpuinfo_operations = {
318     + .open = cpuinfo_open,
319     + .read = seq_read,
320     + .llseek = seq_lseek,
321     + .release = seq_release,
322     };
323    
324     -static void *devinfo_start(struct seq_file *f, loff_t *pos)
325     +static int devinfo_show(struct seq_file *f, void *v)
326     {
327     - struct devinfo_state *info = f->private;
328     + int i = *(loff_t *) v;
329    
330     - if (*pos) {
331     - if ((info) && (*pos <= info->num_records))
332     - return info;
333     - return NULL;
334     + if (i < CHRDEV_MAJOR_HASH_SIZE) {
335     + if (i == 0)
336     + seq_printf(f, "Character devices:\n");
337     + chrdev_show(f, i);
338     + } else {
339     + i -= CHRDEV_MAJOR_HASH_SIZE;
340     + if (i == 0)
341     + seq_printf(f, "\nBlock devices:\n");
342     + blkdev_show(f, i);
343     }
344     - info = kmalloc(sizeof(*info), GFP_KERNEL);
345     - f->private = info;
346     - info->chrdev = acquire_chrdev_list();
347     - info->blkdev = acquire_blkdev_list();
348     - info->state = CHR_HDR;
349     - info->num_records = count_chrdev_list();
350     - info->num_records += count_blkdev_list();
351     - info->num_records += 2; /* Character and Block headers */
352     - *pos = 1;
353     - info->cur_record = *pos;
354     - return info;
355     + return 0;
356     }
357    
358     -static void *devinfo_next(struct seq_file *f, void *v, loff_t *pos)
359     +static void *devinfo_start(struct seq_file *f, loff_t *pos)
360     {
361     - int idummy;
362     - char *ndummy;
363     - struct devinfo_state *info = f->private;
364     -
365     - switch (info->state) {
366     - case CHR_HDR:
367     - info->state = CHR_LIST;
368     - (*pos)++;
369     - /*fallthrough*/
370     - case CHR_LIST:
371     - if (get_chrdev_info(info->chrdev,&idummy,&ndummy)) {
372     - /*
373     - * The character dev list is complete
374     - */
375     - info->state = BLK_HDR;
376     - } else {
377     - info->chrdev = get_next_chrdev(info->chrdev);
378     - }
379     - (*pos)++;
380     - break;
381     - case BLK_HDR:
382     - info->state = BLK_LIST;
383     - (*pos)++;
384     - /*fallthrough*/
385     - case BLK_LIST:
386     - if (get_blkdev_info(info->blkdev,&idummy,&ndummy)) {
387     - /*
388     - * The block dev list is complete
389     - */
390     - info->state = DEVINFO_DONE;
391     - } else {
392     - info->blkdev = get_next_blkdev(info->blkdev);
393     - }
394     - (*pos)++;
395     - break;
396     - case DEVINFO_DONE:
397     - (*pos)++;
398     - info->cur_record = *pos;
399     - info = NULL;
400     - break;
401     - default:
402     - break;
403     - }
404     - if (info)
405     - info->cur_record = *pos;
406     - return info;
407     + if (*pos < (BLKDEV_MAJOR_HASH_SIZE + CHRDEV_MAJOR_HASH_SIZE))
408     + return pos;
409     + return NULL;
410     }
411    
412     -static void devinfo_stop(struct seq_file *f, void *v)
413     +static void *devinfo_next(struct seq_file *f, void *v, loff_t *pos)
414     {
415     - struct devinfo_state *info = f->private;
416     -
417     - if (info) {
418     - release_chrdev_list(info->chrdev);
419     - release_blkdev_list(info->blkdev);
420     - f->private = NULL;
421     - kfree(info);
422     - }
423     + (*pos)++;
424     + if (*pos >= (BLKDEV_MAJOR_HASH_SIZE + CHRDEV_MAJOR_HASH_SIZE))
425     + return NULL;
426     + return pos;
427     }
428    
429     -static int devinfo_show(struct seq_file *f, void *arg)
430     +static void devinfo_stop(struct seq_file *f, void *v)
431     {
432     - int major;
433     - char *name;
434     - struct devinfo_state *info = f->private;
435     -
436     - switch(info->state) {
437     - case CHR_HDR:
438     - seq_printf(f,"Character devices:\n");
439     - /* fallthrough */
440     - case CHR_LIST:
441     - if (!get_chrdev_info(info->chrdev,&major,&name))
442     - seq_printf(f,"%3d %s\n",major,name);
443     - break;
444     - case BLK_HDR:
445     - seq_printf(f,"\nBlock devices:\n");
446     - /* fallthrough */
447     - case BLK_LIST:
448     - if (!get_blkdev_info(info->blkdev,&major,&name))
449     - seq_printf(f,"%3d %s\n",major,name);
450     - break;
451     - default:
452     - break;
453     - }
454     -
455     - return 0;
456     + /* Nothing to do */
457     }
458    
459     -static struct seq_operations devinfo_op = {
460     - .start = devinfo_start,
461     - .next = devinfo_next,
462     - .stop = devinfo_stop,
463     - .show = devinfo_show,
464     +static struct seq_operations devinfo_ops = {
465     + .start = devinfo_start,
466     + .next = devinfo_next,
467     + .stop = devinfo_stop,
468     + .show = devinfo_show
469     };
470    
471     -static int devinfo_open(struct inode *inode, struct file *file)
472     +static int devinfo_open(struct inode *inode, struct file *filp)
473     {
474     - return seq_open(file, &devinfo_op);
475     + return seq_open(filp, &devinfo_ops);
476     }
477    
478     static struct file_operations proc_devinfo_operations = {
479     @@ -396,13 +312,6 @@ static struct file_operations proc_devin
480     .release = seq_release,
481     };
482    
483     -static struct file_operations proc_cpuinfo_operations = {
484     - .open = cpuinfo_open,
485     - .read = seq_read,
486     - .llseek = seq_lseek,
487     - .release = seq_release,
488     -};
489     -
490     extern struct seq_operations vmstat_op;
491     static int vmstat_open(struct inode *inode, struct file *file)
492     {
493     --- a/include/linux/fs.h
494     +++ b/include/linux/fs.h
495     @@ -1383,6 +1383,7 @@ extern int bd_claim(struct block_device
496     extern void bd_release(struct block_device *);
497    
498     /* fs/char_dev.c */
499     +#define CHRDEV_MAJOR_HASH_SIZE 255
500     extern int alloc_chrdev_region(dev_t *, unsigned, unsigned, const char *);
501     extern int register_chrdev_region(dev_t, unsigned, const char *);
502     extern int register_chrdev(unsigned int, const char *,
503     @@ -1390,25 +1391,17 @@ extern int register_chrdev(unsigned int,
504     extern int unregister_chrdev(unsigned int, const char *);
505     extern void unregister_chrdev_region(dev_t, unsigned);
506     extern int chrdev_open(struct inode *, struct file *);
507     -extern int get_chrdev_list(char *);
508     -extern void *acquire_chrdev_list(void);
509     -extern int count_chrdev_list(void);
510     -extern void *get_next_chrdev(void *);
511     -extern int get_chrdev_info(void *, int *, char **);
512     -extern void release_chrdev_list(void *);
513     +extern void chrdev_show(struct seq_file *,off_t);
514    
515     /* fs/block_dev.c */
516     +#define BLKDEV_MAJOR_HASH_SIZE 255
517     #define BDEVNAME_SIZE 32 /* Largest string for a blockdev identifier */
518     extern const char *__bdevname(dev_t, char *buffer);
519     extern const char *bdevname(struct block_device *bdev, char *buffer);
520     extern struct block_device *lookup_bdev(const char *);
521     extern struct block_device *open_bdev_excl(const char *, int, void *);
522     extern void close_bdev_excl(struct block_device *);
523     -extern void *acquire_blkdev_list(void);
524     -extern int count_blkdev_list(void);
525     -extern void *get_next_blkdev(void *);
526     -extern int get_blkdev_info(void *, int *, char **);
527     -extern void release_blkdev_list(void *);
528     +extern void blkdev_show(struct seq_file *,off_t);
529    
530     extern void init_special_inode(struct inode *, umode_t, dev_t);
531